diff options
author | Ceridwen <ceridwenv@gmail.com> | 2016-02-15 22:36:02 -0500 |
---|---|---|
committer | Ceridwen <ceridwenv@gmail.com> | 2016-02-15 22:36:02 -0500 |
commit | 54e5ddc279c4281e1612380af67051734ae30064 (patch) | |
tree | efdb59cd69e68a10cf3ce1a0c271524ecc72c341 | |
parent | 329fc88e739e403c4bc0e7bb93f757efd5b49556 (diff) | |
parent | 7a206c6851cd63a4028d6ce384f281f1ee460181 (diff) | |
download | astroid-git-54e5ddc279c4281e1612380af67051734ae30064.tar.gz |
Merge testdata changes and Parameter nodes into zipper.
108 files changed, 478 insertions, 847 deletions
diff --git a/.travis.yml b/.travis.yml index 9075168a..e3a7da10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ install: - $PYTHON_EXE -m pip --version - $PYTHON_EXE -m tox --version script: - - python -m tox -e $TOXENV + - tox -e $TOXENV after_failure: - more .tox/log/* | cat - more .tox/*/log/* | cat @@ -2,6 +2,28 @@ Change log for the astroid package (used to be astng) ===================================================== -- + * Changed the way how parameters are being built + + The old way consisted in having the parameter names, their + defaults and their annotations separated in different components + of the Arguments node. We introduced a new Param node, which holds + the name of a parameter, its default value and its annotation. + If any of the last two values are missing, then that slot will be + filled with a new node kind, Empty, which is used for specifying the + lack of something (None could have been used instead, but that means having + non-AST nodes in the Arguments node). + We're also having support for positional only arguments, for the moment + only in raw_building. + + * We don't support nested arguments in functions in Python 2 + anymore. + + This was dropped in order to simplify the implementation. + When they are encountered, we'll unflatten them into a list + of parameters, as if they were not nested from the beginning. + + * NodeNG.nearest was removed. It's not an API that we were using + and it was buggy. * Dict nodes are constructed with two arguments, keys and values, in the same way that ast.Dict is built. diff --git a/MANIFEST.in b/MANIFEST.in index 4837adf1..eab1f75b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include ChangeLog -include README +include README.rst include COPYING include COPYING.LESSER include tox.ini recursive-include astroid/tests/testdata *.py *.zip *.egg -recursive-include astroid/brain *.py diff --git a/astroid/as_string.py b/astroid/as_string.py index d99aee0a..800617e7 100644 --- a/astroid/as_string.py +++ b/astroid/as_string.py @@ -193,8 +193,8 @@ class AsStringVisitor(object): def visit_excepthandler(self, node): if node.type: if node.name: - excs = 'except %s, %s' % (node.type.accept(self), - node.name.accept(self)) + excs = 'except %s as %s' % (node.type.accept(self), + node.name.accept(self)) else: excs = 'except %s' % node.type.accept(self) else: @@ -442,17 +442,6 @@ class AsStringVisitor(object): class AsStringVisitor3(AsStringVisitor): """AsStringVisitor3 overwrites some AsStringVisitor methods""" - def visit_excepthandler(self, node): - if node.type: - if node.name: - excs = 'except %s as %s' % (node.type.accept(self), - node.name.accept(self)) - else: - excs = 'except %s' % node.type.accept(self) - else: - excs = 'except' - return '%s:\n%s' % (excs, self._stmt_list(node.body)) - def visit_nonlocal(self, node): """return an astroid.Nonlocal node as string""" return 'nonlocal %s' % ', '.join(node.names) diff --git a/astroid/inference.py b/astroid/inference.py index 1a7ce413..e4074bc1 100644 --- a/astroid/inference.py +++ b/astroid/inference.py @@ -698,6 +698,7 @@ def infer_arguments(self, context=None, nodes=None): @infer.register(treeabc.AssignName) @infer.register(treeabc.AssignAttr) +@infer.register(treeabc.Parameter) @decorators.path_wrapper def infer_assign(self, context=None): """infer a AssignName/AssignAttr: need to inspect the RHS part of the diff --git a/astroid/interpreter/lookup.py b/astroid/interpreter/lookup.py index d8e5931a..20fda77a 100644 --- a/astroid/interpreter/lookup.py +++ b/astroid/interpreter/lookup.py @@ -238,6 +238,7 @@ def locals_new_scope(node, locals_): @_get_locals.register(treeabc.DelName) @_get_locals.register(treeabc.FunctionDef) @_get_locals.register(treeabc.ClassDef) +@_get_locals.register(treeabc.Parameter) def locals_name(node, locals_): '''These nodes add a name to the local variables. AssignName and DelName have no children while FunctionDef and ClassDef start a @@ -287,9 +288,11 @@ def locals_import_from(node, locals_): # Don't add future imports to locals. if node.modname == '__future__': return - # Inherited code, I don't know why this function sorts this list. + + # Sort the list for having the locals ordered by their first + # appearance. def sort_locals(my_list): - my_list.sort(key=lambda node: node.fromlineno) + my_list.sort(key=lambda node: node.fromlineno or 0) for name, asname in node.names: if name == '*': diff --git a/astroid/interpreter/scope.py b/astroid/interpreter/scope.py index 4cca5c5c..47fb3a0c 100644 --- a/astroid/interpreter/scope.py +++ b/astroid/interpreter/scope.py @@ -41,19 +41,23 @@ def _scope_by_parent(parent, node): # in order to decouple the implementation for the normal cases.
+def _node_arguments(node):
+ for arg in itertools.chain(node.positional_and_keyword, node.keyword_only,
+ (node.vararg, ), (node.kwarg, )):
+ if arg and arg.annotation:
+ yield arg
+
+
@_scope_by_parent.register(treeabc.Arguments)
def _scope_by_argument_parent(parent, node):
args = parent
- if node in itertools.chain(args.defaults, args.kw_defaults):
- return args.parent.parent.scope()
- if six.PY3:
- look_for = itertools.chain(
- (args.kwargannotation, ),
- (args.varargannotation, ),
- args.annotations)
- if node in look_for:
+ for param in itertools.chain(args.positional_and_keyword, args.keyword_only):
+ if param.default == node:
return args.parent.parent.scope()
+ if six.PY3 and node in _node_arguments(args):
+ return args.parent.parent.scope()
+
@_scope_by_parent.register(treeabc.FunctionDef)
def _scope_by_function_parent(parent, node):
diff --git a/astroid/nodes.py b/astroid/nodes.py index 1aea53f2..6fb37652 100644 --- a/astroid/nodes.py +++ b/astroid/nodes.py @@ -40,9 +40,9 @@ from astroid.tree.node_classes import ( Arguments, AssignAttr, Assert, Assign, AssignName, AugAssign, Repr, BinOp, BoolOp, Break, Call, Compare, Comprehension, Const, Continue, Decorators, DelAttr, DelName, Delete, - Dict, Expr, Ellipsis, ExceptHandler, Exec, ExtSlice, For, + Dict, Empty, Expr, Ellipsis, ExceptHandler, Exec, ExtSlice, For, ImportFrom, Attribute, Global, If, IfExp, Import, Index, Keyword, - List, Name, NameConstant, Nonlocal, Pass, Print, Raise, Return, Set, Slice, + List, Name, NameConstant, Nonlocal, Pass, Parameter, Print, Raise, Return, Set, Slice, Starred, Subscript, TryExcept, TryFinally, Tuple, UnaryOp, While, With, WithItem, Yield, YieldFrom, AsyncFor, Await, AsyncWith, # Node not present in the builtin ast module. @@ -74,7 +74,7 @@ ALL_NODE_CLASSES = ( Lambda, List, ListComp, Name, NameConstant, Nonlocal, Module, - Pass, Print, + Parameter, Pass, Print, Raise, ReservedName, Return, Set, SetComp, Slice, Starred, Subscript, TryExcept, TryFinally, Tuple, diff --git a/astroid/protocols.py b/astroid/protocols.py index eada9764..7fdc6e29 100644 --- a/astroid/protocols.py +++ b/astroid/protocols.py @@ -304,6 +304,7 @@ def mulass_assigned_stmts(self, nodes, node=None, context=None, assign_path=None @assigned_stmts.register(treeabc.AssignName) @assigned_stmts.register(treeabc.AssignAttr) +@assigned_stmts.register(treeabc.Parameter) def assend_assigned_stmts(self, nodes, node=None, context=None, assign_path=None): return self.parent.assigned_stmts(self, context=context) @@ -311,7 +312,7 @@ def assend_assigned_stmts(self, nodes, node=None, context=None, assign_path=None def _arguments_infer_argname(self, name, context, nodes): # arguments information may be missing, in which case we can't do anything # more - if not (self.args or self.vararg or self.kwarg): + if not self.args and (not self.vararg and not self.kwarg): yield util.Uninferable return # first argument of instance/class method @@ -336,10 +337,10 @@ def _arguments_infer_argname(self, name, context, nodes): return # TODO: just provide the type here, no need to have an empty Dict. - if name == self.vararg: + if self.vararg and name == self.vararg.name: yield nodes.Tuple(parent=self) return - if name == self.kwarg: + if self.kwarg and name == self.kwarg.name: yield nodes.Dict(parent=self) return # if there is a default value, yield it. And then yield Uninferable to reflect diff --git a/astroid/raw_building.py b/astroid/raw_building.py index f3871143..bccd83da 100644 --- a/astroid/raw_building.py +++ b/astroid/raw_building.py @@ -319,65 +319,71 @@ def ast_from_function(func, built_objects, module, name=None, parent=None): itertools.groupby(signature.parameters.values(), operator.attrgetter('kind'))} - def extract_args(parameters, parent): - '''Takes an iterator over Parameter objects and returns three - sequences, arg names, default values, and annotations. - - ''' - names = [] - defaults = [] - annotations = [] + def _extract_args(parameters, parent): + """Generate an iterator of Parameter nodes from a list of inspect.Parameter objects.""" for parameter in parameters: - names.append(parameter.name) + param = node_classes.Parameter(name=parameter.name, + col_offset=parent.col_offset, + lineno=parent.lineno, + parent=parent) + default = node_classes.Empty + annotation = node_classes.Empty if parameter.default is not _Parameter.empty: - defaults.extend(_ast_from_object(parameter.default, built_objects, module, parent=parent)) + default = _ast_from_object(parameter.default, built_objects, + module, parent=parent) + if parameter.annotation is not _Parameter.empty: - annotations.extend(_ast_from_object(parameter.annotation, built_objects, module, parent=parent)) - else: - annotations.append(None) - return names, defaults, annotations + annotation = _ast_from_object(parameter.annotation, built_objects, + module, parent=parent) - def extract_vararg(parameter): - '''Takes a single-element iterator possibly containing a Parameter and - returns a name and an annotation. + param.postinit(default=default, annotation=annotation) + yield param - ''' + def _extract_vararg(parameter, parent): + """Build a variadic Parameter node from an inspect.Parameter object.""" try: - return parameter[0].name + parameter = parameter[0] except IndexError: - return None - - vararg = parameters.get(_Parameter.VAR_POSITIONAL, ()) - kwarg = parameters.get(_Parameter.VAR_KEYWORD, ()) - vararg_name = extract_vararg(vararg) - kwarg_name = extract_vararg(kwarg) - args_node = node_classes.Arguments(vararg=vararg_name, kwarg=kwarg_name, parent=func_node) - - # This ignores POSITIONAL_ONLY args, because they only appear in - # functions implemented in C and can't be mimicked by any Python - # function. - names, defaults, annotations = extract_args(parameters.get(_Parameter.POSITIONAL_OR_KEYWORD, ()), args_node) - kwonlynames, kw_defaults, kwonly_annotations = extract_args(parameters.get(_Parameter.KEYWORD_ONLY, ()), args_node) - args = [node_classes.AssignName(name=n, parent=args_node) for n in names] - kwonlyargs = [node_classes.AssignName(name=n, parent=args_node) for n in kwonlynames] - if vararg_name and vararg[0].annotation is not _Parameter.empty: - varargannotation = vararg.annotation - else: - varargannotation = None - if kwarg_name and kwarg[0].annotation is not _Parameter.empty: - kwargannotation = kwarg.annotation - else: - kwargannotation = None + return node_classes.Empty + + if parameter.annotation is not _Parameter.empty: + annotation = _ast_from_object(parameter.annotation, + built_objects, module, parent=parent)[0] + else: + annotation = node_classes.Empty + + param = node_classes.Parameter(name=parameter.name, + lineno=parent.lineno, + col_offset=parent.col_offset, + parent=parent) + param.postinit(annotation=annotation, default=node_classes.Empty) + return param + + args_node = node_classes.Arguments(parent=func_node) + args = _extract_args(parameters.get(_Parameter.POSITIONAL_OR_KEYWORD, ()), + args_node) + keyword_only = _extract_args(parameters.get(_Parameter.KEYWORD_ONLY, ()), + args_node) + positional_only = _extract_args(parameters.get(_Parameter.POSITIONAL_ONLY, ()), + args_node) + python_vararg = parameters.get(_Parameter.VAR_POSITIONAL, ()) + python_kwarg = parameters.get(_Parameter.VAR_KEYWORD, ()) + vararg = _extract_vararg(python_vararg, args_node) + kwarg = _extract_vararg(python_kwarg, args_node) + returns = None if signature.return_annotation is not _Parameter.empty: returns = _ast_from_object(signature.return_annotation, built_objects, module, parent=func_node)[0] - args_node.postinit(args, defaults, kwonlyargs, kw_defaults, - annotations, kwonly_annotations, - varargannotation, kwargannotation) + args_node.postinit(args=list(args), + vararg=vararg, + kwarg=kwarg, + keyword_only=list(keyword_only), + positional_only=list(positional_only)) func_node.postinit(args=args_node, body=[], returns=returns) + for name in set(dir(func)) - set(dir(type(func))): # This checks against method special attributes because # methods are also dispatched through this function. diff --git a/astroid/test_utils.py b/astroid/test_utils.py index b15ab766..ff81cd59 100644 --- a/astroid/test_utils.py +++ b/astroid/test_utils.py @@ -19,6 +19,7 @@ _TRANSIENT_FUNCTION = '__' # when calling extract_node. _STATEMENT_SELECTOR = '#@' + def _extract_expressions(node): """Find expressions in a call to _TRANSIENT_FUNCTION and extract them. @@ -46,8 +47,18 @@ def _extract_expressions(node): child = getattr(node.parent, name) if isinstance(child, (list, tuple)): for idx, compound_child in enumerate(child): - if compound_child is node: + + # Can't find a cleaner way to do this. + if isinstance(compound_child, nodes.Parameter): + if compound_child.default is node: + child[idx].default = real_expr + elif compound_child.annotation is node: + child[idx].annotation = real_expr + else: + child[idx] = real_expr + elif compound_child is node: child[idx] = real_expr + elif child is node: setattr(node.parent, name, real_expr) yield real_expr diff --git a/astroid/tests/resources.py b/astroid/tests/resources.py index 6a29b54e..1390088c 100644 --- a/astroid/tests/resources.py +++ b/astroid/tests/resources.py @@ -15,8 +15,12 @@ # # You should have received a copy of the GNU Lesser General Public License along # with astroid. If not, see <http://www.gnu.org/licenses/>. +import binascii +import contextlib import os import sys +import shutil +import tempfile import pkg_resources import six @@ -25,12 +29,31 @@ from astroid import builder from astroid import MANAGER -DATA_DIR = 'testdata/python{}/'.format(sys.version_info[0]) +DATA_DIR = 'testdata' BUILTINS = six.moves.builtins.__name__ + +@contextlib.contextmanager +def _temporary_file(): + name = binascii.hexlify(os.urandom(5)).decode() + path = find(name) + try: + yield path + finally: + os.remove(path) + +@contextlib.contextmanager +def tempfile_with_content(content): + with _temporary_file() as tmp: + with open(tmp, 'wb') as stream: + stream.write(content) + yield tmp + + def find(name): return pkg_resources.resource_filename( - 'astroid.tests', os.path.normpath(os.path.join(DATA_DIR, name))) + 'astroid.tests', + os.path.normpath(os.path.join(DATA_DIR, name))) def build_file(path, modname=None): diff --git a/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg b/astroid/tests/testdata/data/MyPyPa-0.1.0-py2.5.egg Binary files differindex f62599c7..f62599c7 100644 --- a/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg +++ b/astroid/tests/testdata/data/MyPyPa-0.1.0-py2.5.egg diff --git a/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip b/astroid/tests/testdata/data/MyPyPa-0.1.0-py2.5.zip Binary files differindex f62599c7..f62599c7 100644 --- a/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip +++ b/astroid/tests/testdata/data/MyPyPa-0.1.0-py2.5.zip diff --git a/astroid/tests/testdata/python3/data/SSL1/Connection1.py b/astroid/tests/testdata/data/SSL1/Connection1.py index 7373271d..7373271d 100644 --- a/astroid/tests/testdata/python3/data/SSL1/Connection1.py +++ b/astroid/tests/testdata/data/SSL1/Connection1.py diff --git a/astroid/tests/testdata/python3/data/SSL1/__init__.py b/astroid/tests/testdata/data/SSL1/__init__.py index c83ededc..c83ededc 100644 --- a/astroid/tests/testdata/python3/data/SSL1/__init__.py +++ b/astroid/tests/testdata/data/SSL1/__init__.py diff --git a/astroid/tests/testdata/python2/data/__init__.py b/astroid/tests/testdata/data/__init__.py index 332e2e72..332e2e72 100644 --- a/astroid/tests/testdata/python2/data/__init__.py +++ b/astroid/tests/testdata/data/__init__.py diff --git a/astroid/tests/testdata/python2/data/absimp/__init__.py b/astroid/tests/testdata/data/absimp/__init__.py index b98444df..b98444df 100644 --- a/astroid/tests/testdata/python2/data/absimp/__init__.py +++ b/astroid/tests/testdata/data/absimp/__init__.py diff --git a/astroid/tests/testdata/python2/data/absimp/sidepackage/__init__.py b/astroid/tests/testdata/data/absimp/sidepackage/__init__.py index 239499a6..239499a6 100644 --- a/astroid/tests/testdata/python2/data/absimp/sidepackage/__init__.py +++ b/astroid/tests/testdata/data/absimp/sidepackage/__init__.py diff --git a/astroid/tests/testdata/python2/data/absimp/string.py b/astroid/tests/testdata/data/absimp/string.py index e68e7496..e68e7496 100644 --- a/astroid/tests/testdata/python2/data/absimp/string.py +++ b/astroid/tests/testdata/data/absimp/string.py diff --git a/astroid/tests/testdata/python2/data/absimport.py b/astroid/tests/testdata/data/absimport.py index f98effa6..f98effa6 100644 --- a/astroid/tests/testdata/python2/data/absimport.py +++ b/astroid/tests/testdata/data/absimport.py diff --git a/astroid/tests/testdata/python2/data/all.py b/astroid/tests/testdata/data/all.py index 23f7d2b6..dd86abc5 100644 --- a/astroid/tests/testdata/python2/data/all.py +++ b/astroid/tests/testdata/data/all.py @@ -4,6 +4,6 @@ _bla = 2 other = 'o' class Aaa: pass -def func(): print 'yo' +def func(): pass __all__ = 'Aaa', '_bla', 'name' diff --git a/astroid/tests/testdata/python2/data/appl/__init__.py b/astroid/tests/testdata/data/appl/__init__.py index d652ffd9..d652ffd9 100644 --- a/astroid/tests/testdata/python2/data/appl/__init__.py +++ b/astroid/tests/testdata/data/appl/__init__.py diff --git a/astroid/tests/testdata/python3/data/appl/myConnection.py b/astroid/tests/testdata/data/appl/myConnection.py index 49269534..398484ad 100644 --- a/astroid/tests/testdata/python3/data/appl/myConnection.py +++ b/astroid/tests/testdata/data/appl/myConnection.py @@ -1,3 +1,4 @@ +from __future__ import print_function from data import SSL1 class MyConnection(SSL1.Connection): diff --git a/astroid/tests/testdata/python2/data/descriptor_crash.py b/astroid/tests/testdata/data/descriptor_crash.py index 11fbb4a2..11fbb4a2 100644 --- a/astroid/tests/testdata/python2/data/descriptor_crash.py +++ b/astroid/tests/testdata/data/descriptor_crash.py diff --git a/astroid/tests/testdata/python2/data/email.py b/astroid/tests/testdata/data/email.py index dc593564..dc593564 100644 --- a/astroid/tests/testdata/python2/data/email.py +++ b/astroid/tests/testdata/data/email.py diff --git a/astroid/tests/testdata/python2/data/find_test/__init__.py b/astroid/tests/testdata/data/find_test/__init__.py index e69de29b..e69de29b 100644 --- a/astroid/tests/testdata/python2/data/find_test/__init__.py +++ b/astroid/tests/testdata/data/find_test/__init__.py diff --git a/astroid/tests/testdata/python2/data/find_test/module.py b/astroid/tests/testdata/data/find_test/module.py index e69de29b..e69de29b 100644 --- a/astroid/tests/testdata/python2/data/find_test/module.py +++ b/astroid/tests/testdata/data/find_test/module.py diff --git a/astroid/tests/testdata/python2/data/find_test/module2.py b/astroid/tests/testdata/data/find_test/module2.py index e69de29b..e69de29b 100644 --- a/astroid/tests/testdata/python2/data/find_test/module2.py +++ b/astroid/tests/testdata/data/find_test/module2.py diff --git a/astroid/tests/testdata/python2/data/find_test/noendingnewline.py b/astroid/tests/testdata/data/find_test/noendingnewline.py index e69de29b..e69de29b 100644 --- a/astroid/tests/testdata/python2/data/find_test/noendingnewline.py +++ b/astroid/tests/testdata/data/find_test/noendingnewline.py diff --git a/astroid/tests/testdata/python2/data/find_test/nonregr.py b/astroid/tests/testdata/data/find_test/nonregr.py index e69de29b..e69de29b 100644 --- a/astroid/tests/testdata/python2/data/find_test/nonregr.py +++ b/astroid/tests/testdata/data/find_test/nonregr.py diff --git a/astroid/tests/testdata/python2/data/format.py b/astroid/tests/testdata/data/format.py index 73797061..73797061 100644 --- a/astroid/tests/testdata/python2/data/format.py +++ b/astroid/tests/testdata/data/format.py diff --git a/astroid/tests/testdata/python2/data/lmfp/__init__.py b/astroid/tests/testdata/data/lmfp/__init__.py index 74b26b82..74b26b82 100644 --- a/astroid/tests/testdata/python2/data/lmfp/__init__.py +++ b/astroid/tests/testdata/data/lmfp/__init__.py diff --git a/astroid/tests/testdata/python2/data/lmfp/foo.py b/astroid/tests/testdata/data/lmfp/foo.py index 8f7de1e8..8f7de1e8 100644 --- a/astroid/tests/testdata/python2/data/lmfp/foo.py +++ b/astroid/tests/testdata/data/lmfp/foo.py diff --git a/astroid/tests/testdata/python2/data/module.py b/astroid/tests/testdata/data/module.py index 118b16f9..84185cfa 100644 --- a/astroid/tests/testdata/python2/data/module.py +++ b/astroid/tests/testdata/data/module.py @@ -29,7 +29,7 @@ class YO: def __init__(self): try: self.yo = 1 - except ValueError, ex: + except ValueError as ex: pass except (NameError, TypeError): raise XXXError() @@ -66,7 +66,7 @@ class YOUPI(YO): def class_method(cls): """class method test""" - exec a in b + pass class_method = classmethod(class_method) @@ -83,6 +83,6 @@ def four_args(a, b, c, d): d = ((a) and (b)) or (c) else: c = ((a) and (b)) or (d) - map(lambda x, y: (y, x), a) + list(map(lambda x, y: (y, x), a)) redirect = four_args diff --git a/astroid/tests/testdata/python2/data/module1abs/__init__.py b/astroid/tests/testdata/data/module1abs/__init__.py index 42949a44..42949a44 100644 --- a/astroid/tests/testdata/python2/data/module1abs/__init__.py +++ b/astroid/tests/testdata/data/module1abs/__init__.py diff --git a/astroid/tests/testdata/python2/data/module1abs/core.py b/astroid/tests/testdata/data/module1abs/core.py index de101117..de101117 100644 --- a/astroid/tests/testdata/python2/data/module1abs/core.py +++ b/astroid/tests/testdata/data/module1abs/core.py diff --git a/astroid/tests/testdata/python3/data/module2.py b/astroid/tests/testdata/data/module2.py index 582ccd98..72d08c51 100644 --- a/astroid/tests/testdata/python3/data/module2.py +++ b/astroid/tests/testdata/data/module2.py @@ -76,8 +76,6 @@ b = (1) | (((2) & (3)) ^ (8)) bb = ((1) | (two)) | (6) ccc = ((one) & (two)) & (three) dddd = ((x) ^ (o)) ^ (r) -exec('c = 3') -exec('c = 3', {}, {}) def raise_string(a=2, *args, **kwargs): raise Exception('yo') diff --git a/astroid/tests/testdata/python3/data/noendingnewline.py b/astroid/tests/testdata/data/noendingnewline.py index e17b92cc..e17b92cc 100644 --- a/astroid/tests/testdata/python3/data/noendingnewline.py +++ b/astroid/tests/testdata/data/noendingnewline.py diff --git a/astroid/tests/testdata/python2/data/nonregr.py b/astroid/tests/testdata/data/nonregr.py index 813469fe..813469fe 100644 --- a/astroid/tests/testdata/python2/data/nonregr.py +++ b/astroid/tests/testdata/data/nonregr.py diff --git a/astroid/tests/testdata/python3/data/notall.py b/astroid/tests/testdata/data/notall.py index 9d35aa3a..9d35aa3a 100644 --- a/astroid/tests/testdata/python3/data/notall.py +++ b/astroid/tests/testdata/data/notall.py diff --git a/astroid/tests/testdata/python2/data/notamodule/file.py b/astroid/tests/testdata/data/notamodule/file.py index e69de29b..e69de29b 100644 --- a/astroid/tests/testdata/python2/data/notamodule/file.py +++ b/astroid/tests/testdata/data/notamodule/file.py diff --git a/astroid/tests/testdata/python2/data/package/__init__.py b/astroid/tests/testdata/data/package/__init__.py index 575d18b1..575d18b1 100644 --- a/astroid/tests/testdata/python2/data/package/__init__.py +++ b/astroid/tests/testdata/data/package/__init__.py diff --git a/astroid/tests/testdata/python2/data/package/absimport.py b/astroid/tests/testdata/data/package/absimport.py index 33ed117c..33ed117c 100644 --- a/astroid/tests/testdata/python2/data/package/absimport.py +++ b/astroid/tests/testdata/data/package/absimport.py diff --git a/astroid/tests/testdata/python2/data/package/hello.py b/astroid/tests/testdata/data/package/hello.py index b154c844..b154c844 100644 --- a/astroid/tests/testdata/python2/data/package/hello.py +++ b/astroid/tests/testdata/data/package/hello.py diff --git a/astroid/tests/testdata/python2/data/package/import_package_subpackage_module.py b/astroid/tests/testdata/data/package/import_package_subpackage_module.py index ad442c16..ad442c16 100644 --- a/astroid/tests/testdata/python2/data/package/import_package_subpackage_module.py +++ b/astroid/tests/testdata/data/package/import_package_subpackage_module.py diff --git a/astroid/tests/testdata/python2/data/package/subpackage/__init__.py b/astroid/tests/testdata/data/package/subpackage/__init__.py index dc4782e6..dc4782e6 100644 --- a/astroid/tests/testdata/python2/data/package/subpackage/__init__.py +++ b/astroid/tests/testdata/data/package/subpackage/__init__.py diff --git a/astroid/tests/testdata/python2/data/package/subpackage/module.py b/astroid/tests/testdata/data/package/subpackage/module.py index 4b7244ba..4b7244ba 100644 --- a/astroid/tests/testdata/python2/data/package/subpackage/module.py +++ b/astroid/tests/testdata/data/package/subpackage/module.py diff --git a/astroid/tests/testdata/python2/data/recursion.py b/astroid/tests/testdata/data/recursion.py index a34dad32..85f65134 100644 --- a/astroid/tests/testdata/python2/data/recursion.py +++ b/astroid/tests/testdata/data/recursion.py @@ -1,3 +1,3 @@ -""" For issue #25 """
-class Base(object):
+""" For issue #25 """ +class Base(object): pass
\ No newline at end of file diff --git a/astroid/tests/testdata/python2/data/unicode_package/__init__.py b/astroid/tests/testdata/data/unicode_package/__init__.py index 713e5591..713e5591 100644 --- a/astroid/tests/testdata/python2/data/unicode_package/__init__.py +++ b/astroid/tests/testdata/data/unicode_package/__init__.py diff --git a/astroid/tests/testdata/python2/data/unicode_package/core/__init__.py b/astroid/tests/testdata/data/unicode_package/core/__init__.py index e69de29b..e69de29b 100644 --- a/astroid/tests/testdata/python2/data/unicode_package/core/__init__.py +++ b/astroid/tests/testdata/data/unicode_package/core/__init__.py diff --git a/astroid/tests/testdata/python2/data/SSL1/Connection1.py b/astroid/tests/testdata/python2/data/SSL1/Connection1.py deleted file mode 100644 index 6bbb1302..00000000 --- a/astroid/tests/testdata/python2/data/SSL1/Connection1.py +++ /dev/null @@ -1,14 +0,0 @@ -"""M2Crypto.SSL.Connection - -Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" -from __future__ import print_function -RCS_id='$Id: Connection1.py,v 1.1 2005-06-13 20:55:22 syt Exp $' - -#Some code deleted here - -class Connection: - - """An SSL connection.""" - - def __init__(self, ctx, sock=None): - print('init Connection') diff --git a/astroid/tests/testdata/python2/data/SSL1/__init__.py b/astroid/tests/testdata/python2/data/SSL1/__init__.py deleted file mode 100644 index a007b049..00000000 --- a/astroid/tests/testdata/python2/data/SSL1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from Connection1 import Connection diff --git a/astroid/tests/testdata/python2/data/appl/myConnection.py b/astroid/tests/testdata/python2/data/appl/myConnection.py deleted file mode 100644 index 5b24b259..00000000 --- a/astroid/tests/testdata/python2/data/appl/myConnection.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import print_function -from data import SSL1 -class MyConnection(SSL1.Connection): - - """An SSL connection.""" - - def __init__(self, dummy): - print('MyConnection init') - -if __name__ == '__main__': - myConnection = MyConnection(' ') - raw_input('Press Enter to continue...') diff --git a/astroid/tests/testdata/python2/data/invalid_encoding.py b/astroid/tests/testdata/python2/data/invalid_encoding.py deleted file mode 100644 index dddd208e..00000000 --- a/astroid/tests/testdata/python2/data/invalid_encoding.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: lala -*-
\ No newline at end of file diff --git a/astroid/tests/testdata/python2/data/module2.py b/astroid/tests/testdata/python2/data/module2.py deleted file mode 100644 index 0a1bd1ad..00000000 --- a/astroid/tests/testdata/python2/data/module2.py +++ /dev/null @@ -1,143 +0,0 @@ -from data.module import YO, YOUPI -import data - - -class Specialization(YOUPI, YO): - pass - - - -class Metaclass(type): - pass - - - -class Interface: - pass - - - -class MyIFace(Interface): - pass - - - -class AnotherIFace(Interface): - pass - - - -class MyException(Exception): - pass - - - -class MyError(MyException): - pass - - - -class AbstractClass(object): - - def to_override(self, whatever): - raise NotImplementedError() - - def return_something(self, param): - if param: - return 'toto' - return - - - -class Concrete0: - __implements__ = MyIFace - - - -class Concrete1: - __implements__ = (MyIFace, AnotherIFace) - - - -class Concrete2: - __implements__ = (MyIFace, AnotherIFace) - - - -class Concrete23(Concrete1): - pass - -del YO.member -del YO -[SYN1, SYN2] = (Concrete0, Concrete1) -assert '1' -b = (1) | (((2) & (3)) ^ (8)) -bb = ((1) | (two)) | (6) -ccc = ((one) & (two)) & (three) -dddd = ((x) ^ (o)) ^ (r) -exec 'c = 3' -exec 'c = 3' in {}, {} - -def raise_string(a=2, *args, **kwargs): - raise Exception, 'yo' - yield 'coucou' - yield -a = (b) + (2) -c = (b) * (2) -c = (b) / (2) -c = (b) // (2) -c = (b) - (2) -c = (b) % (2) -c = (b) ** (2) -c = (b) << (2) -c = (b) >> (2) -c = ~b -c = not b -d = [c] -e = d[:] -e = d[a:b:c] -raise_string(*args, **kwargs) -print >> stream, 'bonjour' -print >> stream, 'salut', - -def make_class(any, base=data.module.YO, *args, **kwargs): - """check base is correctly resolved to Concrete0""" - - - class Aaaa(base): - """dynamic class""" - - - return Aaaa -from os.path import abspath -import os as myos - - -class A: - pass - - - -class A(A): - pass - - -def generator(): - """A generator.""" - yield - -def not_a_generator(): - """A function that contains generator, but is not one.""" - - def generator(): - yield - genl = lambda : (yield) - -def with_metaclass(meta, *bases): - return meta('NewBase', bases, {}) - - -class NotMetaclass(with_metaclass(Metaclass)): - pass - - diff --git a/astroid/tests/testdata/python2/data/noendingnewline.py b/astroid/tests/testdata/python2/data/noendingnewline.py deleted file mode 100644 index e1d6e4a1..00000000 --- a/astroid/tests/testdata/python2/data/noendingnewline.py +++ /dev/null @@ -1,36 +0,0 @@ -import unittest - - -class TestCase(unittest.TestCase): - - def setUp(self): - unittest.TestCase.setUp(self) - - - def tearDown(self): - unittest.TestCase.tearDown(self) - - def testIt(self): - self.a = 10 - self.xxx() - - - def xxx(self): - if False: - pass - print 'a' - - if False: - pass - pass - - if False: - pass - print 'rara' - - -if __name__ == '__main__': - print 'test2' - unittest.main() - - diff --git a/astroid/tests/testdata/python2/data/notall.py b/astroid/tests/testdata/python2/data/notall.py deleted file mode 100644 index 042491e0..00000000 --- a/astroid/tests/testdata/python2/data/notall.py +++ /dev/null @@ -1,7 +0,0 @@ -name = 'a' -_bla = 2 -other = 'o' -class Aaa: pass - -def func(): return 'yo' - diff --git a/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.egg b/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.egg Binary files differdeleted file mode 100644 index f62599c7..00000000 --- a/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.egg +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.zip b/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.zip Binary files differdeleted file mode 100644 index f62599c7..00000000 --- a/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.zip +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/__init__.py b/astroid/tests/testdata/python3/data/__init__.py deleted file mode 100644 index 332e2e72..00000000 --- a/astroid/tests/testdata/python3/data/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__revision__="$Id: __init__.py,v 1.1 2005-06-13 20:55:20 syt Exp $" diff --git a/astroid/tests/testdata/python3/data/absimp/__init__.py b/astroid/tests/testdata/python3/data/absimp/__init__.py deleted file mode 100644 index b98444df..00000000 --- a/astroid/tests/testdata/python3/data/absimp/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""a package with absolute import activated -""" - -from __future__ import absolute_import - diff --git a/astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py b/astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py deleted file mode 100644 index 239499a6..00000000 --- a/astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""a side package with nothing in it -""" - diff --git a/astroid/tests/testdata/python3/data/absimp/string.py b/astroid/tests/testdata/python3/data/absimp/string.py deleted file mode 100644 index e68e7496..00000000 --- a/astroid/tests/testdata/python3/data/absimp/string.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import absolute_import, print_function -import string -print(string) diff --git a/astroid/tests/testdata/python3/data/absimport.py b/astroid/tests/testdata/python3/data/absimport.py deleted file mode 100644 index 88f9d955..00000000 --- a/astroid/tests/testdata/python3/data/absimport.py +++ /dev/null @@ -1,3 +0,0 @@ - -import email -from email import message diff --git a/astroid/tests/testdata/python3/data/all.py b/astroid/tests/testdata/python3/data/all.py deleted file mode 100644 index 587765b5..00000000 --- a/astroid/tests/testdata/python3/data/all.py +++ /dev/null @@ -1,9 +0,0 @@ - -name = 'a' -_bla = 2 -other = 'o' -class Aaa: pass - -def func(): print('yo') - -__all__ = 'Aaa', '_bla', 'name' diff --git a/astroid/tests/testdata/python3/data/appl/__init__.py b/astroid/tests/testdata/python3/data/appl/__init__.py deleted file mode 100644 index d652ffd9..00000000 --- a/astroid/tests/testdata/python3/data/appl/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Init -""" diff --git a/astroid/tests/testdata/python3/data/descriptor_crash.py b/astroid/tests/testdata/python3/data/descriptor_crash.py deleted file mode 100644 index 11fbb4a2..00000000 --- a/astroid/tests/testdata/python3/data/descriptor_crash.py +++ /dev/null @@ -1,11 +0,0 @@ - -import urllib - -class Page(object): - _urlOpen = staticmethod(urllib.urlopen) - - def getPage(self, url): - handle = self._urlOpen(url) - data = handle.read() - handle.close() - return data diff --git a/astroid/tests/testdata/python3/data/email.py b/astroid/tests/testdata/python3/data/email.py deleted file mode 100644 index dc593564..00000000 --- a/astroid/tests/testdata/python3/data/email.py +++ /dev/null @@ -1 +0,0 @@ -"""fake email module to test absolute import doesn't grab this one""" diff --git a/astroid/tests/testdata/python3/data/find_test/__init__.py b/astroid/tests/testdata/python3/data/find_test/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/astroid/tests/testdata/python3/data/find_test/__init__.py +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/find_test/module.py b/astroid/tests/testdata/python3/data/find_test/module.py deleted file mode 100644 index e69de29b..00000000 --- a/astroid/tests/testdata/python3/data/find_test/module.py +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/find_test/module2.py b/astroid/tests/testdata/python3/data/find_test/module2.py deleted file mode 100644 index e69de29b..00000000 --- a/astroid/tests/testdata/python3/data/find_test/module2.py +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/find_test/noendingnewline.py b/astroid/tests/testdata/python3/data/find_test/noendingnewline.py deleted file mode 100644 index e69de29b..00000000 --- a/astroid/tests/testdata/python3/data/find_test/noendingnewline.py +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/find_test/nonregr.py b/astroid/tests/testdata/python3/data/find_test/nonregr.py deleted file mode 100644 index e69de29b..00000000 --- a/astroid/tests/testdata/python3/data/find_test/nonregr.py +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/format.py b/astroid/tests/testdata/python3/data/format.py deleted file mode 100644 index 73797061..00000000 --- a/astroid/tests/testdata/python3/data/format.py +++ /dev/null @@ -1,34 +0,0 @@ -"""A multiline string -""" - -function('aeozrijz\ -earzer', hop) -# XXX write test -x = [i for i in range(5) - if i % 4] - -fonction(1, - 2, - 3, - 4) - -def definition(a, - b, - c): - return a + b + c - -class debile(dict, - object): - pass - -if aaaa: pass -else: - aaaa,bbbb = 1,2 - aaaa,bbbb = bbbb,aaaa -# XXX write test -hop = \ - aaaa - - -__revision__.lower(); - diff --git a/astroid/tests/testdata/python3/data/invalid_encoding.py b/astroid/tests/testdata/python3/data/invalid_encoding.py deleted file mode 100644 index dddd208e..00000000 --- a/astroid/tests/testdata/python3/data/invalid_encoding.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: lala -*-
\ No newline at end of file diff --git a/astroid/tests/testdata/python3/data/lmfp/__init__.py b/astroid/tests/testdata/python3/data/lmfp/__init__.py deleted file mode 100644 index 74b26b82..00000000 --- a/astroid/tests/testdata/python3/data/lmfp/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# force a "direct" python import -from . import foo diff --git a/astroid/tests/testdata/python3/data/lmfp/foo.py b/astroid/tests/testdata/python3/data/lmfp/foo.py deleted file mode 100644 index 8f7de1e8..00000000 --- a/astroid/tests/testdata/python3/data/lmfp/foo.py +++ /dev/null @@ -1,6 +0,0 @@ -import sys -if not getattr(sys, 'bar', None): - sys.just_once = [] -# there used to be two numbers here because -# of a load_module_from_path bug -sys.just_once.append(42) diff --git a/astroid/tests/testdata/python3/data/module.py b/astroid/tests/testdata/python3/data/module.py deleted file mode 100644 index da4d7afb..00000000 --- a/astroid/tests/testdata/python3/data/module.py +++ /dev/null @@ -1,87 +0,0 @@ -"""test module for astroid -""" - -__revision__ = '$Id: module.py,v 1.2 2005-11-02 11:56:54 syt Exp $' -from astroid.tree.node_classes import Name as NameNode -from astroid import modutils -from astroid.utils import * -import os.path -MY_DICT = {} - -def global_access(key, val): - """function test""" - local = 1 - MY_DICT[key] = val - for i in val: - if i: - del MY_DICT[i] - continue - else: - break - else: - return - - -class YO: - """hehe""" - a = 1 - - def __init__(self): - try: - self.yo = 1 - except ValueError as ex: - pass - except (NameError, TypeError): - raise XXXError() - except: - raise - - - -class YOUPI(YO): - class_attr = None - - def __init__(self): - self.member = None - - def method(self): - """method test""" - try: - MY_DICT = {} - local = None - autre = [a for (a, b) in MY_DICT if b] - if b in autre: - return - else: - if a in autre: - return 'hehe' - global_access(local, val=autre) - finally: - return local - - def static_method(): - """static method test""" - assert MY_DICT, '???' - static_method = staticmethod(static_method) - - def class_method(cls): - """class method test""" - exec(a, b) - class_method = classmethod(class_method) - - -def four_args(a, b, c, d): - """four arguments (was nested_args)""" - while 1: - if a: - break - a += +1 - else: - b += -2 - if c: - d = ((a) and (b)) or (c) - else: - c = ((a) and (b)) or (d) - list(map(lambda x, y: (y, x), a)) -redirect = four_args - diff --git a/astroid/tests/testdata/python3/data/module1abs/__init__.py b/astroid/tests/testdata/python3/data/module1abs/__init__.py deleted file mode 100644 index f9d5b686..00000000 --- a/astroid/tests/testdata/python3/data/module1abs/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ - -from . import core -from .core import * -print(sys.version) diff --git a/astroid/tests/testdata/python3/data/module1abs/core.py b/astroid/tests/testdata/python3/data/module1abs/core.py deleted file mode 100644 index de101117..00000000 --- a/astroid/tests/testdata/python3/data/module1abs/core.py +++ /dev/null @@ -1 +0,0 @@ -import sys diff --git a/astroid/tests/testdata/python3/data/nonregr.py b/astroid/tests/testdata/python3/data/nonregr.py deleted file mode 100644 index 78765c85..00000000 --- a/astroid/tests/testdata/python3/data/nonregr.py +++ /dev/null @@ -1,57 +0,0 @@ - - -try: - enumerate = enumerate -except NameError: - - def enumerate(iterable): - """emulates the python2.3 enumerate() function""" - i = 0 - for val in iterable: - yield i, val - i += 1 - -def toto(value): - for k, v in value: - print(v.get('yo')) - - -import imp -fp, mpath, desc = imp.find_module('optparse',a) -s_opt = imp.load_module('std_optparse', fp, mpath, desc) - -class OptionParser(s_opt.OptionParser): - - def parse_args(self, args=None, values=None, real_optparse=False): - if real_optparse: - pass -## return super(OptionParser, self).parse_args() - else: - import optcomp - optcomp.completion(self) - - -class Aaa(object): - """docstring""" - def __init__(self): - self.__setattr__('a','b') - pass - - def one_public(self): - """docstring""" - pass - - def another_public(self): - """docstring""" - pass - -class Ccc(Aaa): - """docstring""" - - class Ddd(Aaa): - """docstring""" - pass - - class Eee(Ddd): - """docstring""" - pass diff --git a/astroid/tests/testdata/python3/data/notamodule/file.py b/astroid/tests/testdata/python3/data/notamodule/file.py deleted file mode 100644 index e69de29b..00000000 --- a/astroid/tests/testdata/python3/data/notamodule/file.py +++ /dev/null diff --git a/astroid/tests/testdata/python3/data/package/__init__.py b/astroid/tests/testdata/python3/data/package/__init__.py deleted file mode 100644 index 575d18b1..00000000 --- a/astroid/tests/testdata/python3/data/package/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""package's __init__ file""" - - -from . import subpackage diff --git a/astroid/tests/testdata/python3/data/package/absimport.py b/astroid/tests/testdata/python3/data/package/absimport.py deleted file mode 100644 index 33ed117c..00000000 --- a/astroid/tests/testdata/python3/data/package/absimport.py +++ /dev/null @@ -1,6 +0,0 @@ -from __future__ import absolute_import, print_function -import import_package_subpackage_module # fail -print(import_package_subpackage_module) - -from . import hello as hola - diff --git a/astroid/tests/testdata/python3/data/package/hello.py b/astroid/tests/testdata/python3/data/package/hello.py deleted file mode 100644 index b154c844..00000000 --- a/astroid/tests/testdata/python3/data/package/hello.py +++ /dev/null @@ -1,2 +0,0 @@ -"""hello module""" - diff --git a/astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py b/astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py deleted file mode 100644 index ad442c16..00000000 --- a/astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py +++ /dev/null @@ -1,49 +0,0 @@ -# pylint: disable-msg=I0011,C0301,W0611 -"""I found some of my scripts trigger off an AttributeError in pylint -0.8.1 (with common 0.12.0 and astroid 0.13.1). - -Traceback (most recent call last): - File "/usr/bin/pylint", line 4, in ? - lint.Run(sys.argv[1:]) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 729, in __init__ - linter.check(args) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 412, in check - self.check_file(filepath, modname, checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 426, in check_file - astroid = self._check_file(filepath, modname, checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 450, in _check_file - self.check_astroid_module(astroid, checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 494, in check_astroid_module - self.astroid_events(astroid, [checker for checker in checkers - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 511, in astroid_events - self.astroid_events(child, checkers, _reversed_checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 511, in astroid_events - self.astroid_events(child, checkers, _reversed_checkers) - File "/usr/lib/python2.4/site-packages/pylint/lint.py", line 508, in astroid_events - checker.visit(astroid) - File "/usr/lib/python2.4/site-packages/logilab/astroid/utils.py", line 84, in visit - method(node) - File "/usr/lib/python2.4/site-packages/pylint/checkers/variables.py", line 295, in visit_import - self._check_module_attrs(node, module, name_parts[1:]) - File "/usr/lib/python2.4/site-packages/pylint/checkers/variables.py", line 357, in _check_module_attrs - self.add_message('E0611', args=(name, module.name), -AttributeError: Import instance has no attribute 'name' - - -You can reproduce it by: -(1) create package structure like the following: - -package/ - __init__.py - subpackage/ - __init__.py - module.py - -(2) in package/__init__.py write: - -import subpackage - -(3) run pylint with a script importing package.subpackage.module. -""" -__revision__ = '$Id: import_package_subpackage_module.py,v 1.1 2005-11-10 15:59:32 syt Exp $' -import package.subpackage.module diff --git a/astroid/tests/testdata/python3/data/package/subpackage/__init__.py b/astroid/tests/testdata/python3/data/package/subpackage/__init__.py deleted file mode 100644 index dc4782e6..00000000 --- a/astroid/tests/testdata/python3/data/package/subpackage/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""package.subpackage""" diff --git a/astroid/tests/testdata/python3/data/package/subpackage/module.py b/astroid/tests/testdata/python3/data/package/subpackage/module.py deleted file mode 100644 index 4b7244ba..00000000 --- a/astroid/tests/testdata/python3/data/package/subpackage/module.py +++ /dev/null @@ -1 +0,0 @@ -"""package.subpackage.module""" diff --git a/astroid/tests/testdata/python3/data/recursion.py b/astroid/tests/testdata/python3/data/recursion.py deleted file mode 100644 index a34dad32..00000000 --- a/astroid/tests/testdata/python3/data/recursion.py +++ /dev/null @@ -1,3 +0,0 @@ -""" For issue #25 """
-class Base(object):
- pass
\ No newline at end of file diff --git a/astroid/tests/testdata/python3/data/unicode_package/__init__.py b/astroid/tests/testdata/python3/data/unicode_package/__init__.py deleted file mode 100644 index 713e5591..00000000 --- a/astroid/tests/testdata/python3/data/unicode_package/__init__.py +++ /dev/null @@ -1 +0,0 @@ -x = "șțîâ"
\ No newline at end of file diff --git a/astroid/tests/testdata/python3/data/unicode_package/core/__init__.py b/astroid/tests/testdata/python3/data/unicode_package/core/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/astroid/tests/testdata/python3/data/unicode_package/core/__init__.py +++ /dev/null diff --git a/astroid/tests/unittest_brain.py b/astroid/tests/unittest_brain.py index 85f6f04c..a12b242e 100644 --- a/astroid/tests/unittest_brain.py +++ b/astroid/tests/unittest_brain.py @@ -84,7 +84,9 @@ class HashlibTest(unittest.TestCase): self.assertIn('block_size', class_obj) self.assertIn('digest_size', class_obj) self.assertEqual(len(class_obj['__init__'].args.args), 2) - self.assertEqual(len(class_obj['__init__'].args.defaults), 1) + default = class_obj['__init__'].args.args[1].default + self.assertIsInstance(default, nodes.Const) + self.assertEqual(default.value, '') self.assertEqual(len(class_obj['update'].args.args), 2) self.assertEqual(len(class_obj['digest'].args.args), 1) self.assertEqual(len(class_obj['hexdigest'].args.args), 1) diff --git a/astroid/tests/unittest_builder.py b/astroid/tests/unittest_builder.py index 206c7da2..813c2e3d 100644 --- a/astroid/tests/unittest_builder.py +++ b/astroid/tests/unittest_builder.py @@ -39,7 +39,41 @@ BUILTINS = six.moves.builtins.__name__ class FromToLineNoTest(unittest.TestCase): def setUp(self): - self.astroid = resources.build_file('data/format.py') + self.astroid = builder.parse(''' + """A multiline string + """ + + function('aeozrijz\ + earzer', hop) + # XXX write test + x = [i for i in range(5) + if i % 4] + + fonction(1, + 2, + 3, + 4) + + def definition(a, + b, + c): + return a + b + c + + class debile(dict, + object): + pass + + if aaaa: pass + else: + aaaa,bbbb = 1,2 + aaaa,bbbb = bbbb,aaaa + # XXX write test + hop = \ + aaaa + + + __revision__.lower(); + ''') def test_callfunc_lineno(self): stmts = self.astroid.body @@ -48,16 +82,16 @@ class FromToLineNoTest(unittest.TestCase): # earzer', hop) discard = stmts[0] self.assertIsInstance(discard, nodes.Expr) - self.assertEqual(discard.fromlineno, 4) + self.assertEqual(discard.fromlineno, 5) self.assertEqual(discard.tolineno, 5) callfunc = discard.value self.assertIsInstance(callfunc, nodes.Call) - self.assertEqual(callfunc.fromlineno, 4) + self.assertEqual(callfunc.fromlineno, 5) self.assertEqual(callfunc.tolineno, 5) name = callfunc.func self.assertIsInstance(name, nodes.Name) - self.assertEqual(name.fromlineno, 4) - self.assertEqual(name.tolineno, 4) + self.assertEqual(name.fromlineno, 5) + self.assertEqual(name.tolineno, 5) strarg = callfunc.args[0] self.assertIsInstance(strarg, nodes.Const) if hasattr(sys, 'pypy_version_info'): @@ -263,10 +297,6 @@ class BuilderTest(unittest.TestCase): with self.assertRaises(exceptions.AstroidSyntaxError): self.builder.string_build('"\\x1"') - def test_missing_newline(self): - """check that a file with no trailing new line is parseable""" - resources.build_file('data/noendingnewline.py') - def test_missing_file(self): with self.assertRaises(exceptions.AstroidBuildingError): resources.build_file('data/inexistant.py') @@ -711,7 +741,8 @@ class FileBuildTest(unittest.TestCase): def test_unknown_encoding(self): with self.assertRaises(exceptions.AstroidSyntaxError): - resources.build_file('data/invalid_encoding.py') + with resources.tempfile_with_content(b'# -*- coding: lala -*-') as tmp: + builder.AstroidBuilder().file_build(tmp) class ModuleBuildTest(resources.SysPathSetup, FileBuildTest): diff --git a/astroid/tests/unittest_modutils.py b/astroid/tests/unittest_modutils.py index 3740aa26..6dfd3bd8 100644 --- a/astroid/tests/unittest_modutils.py +++ b/astroid/tests/unittest_modutils.py @@ -244,6 +244,7 @@ class GetModuleFilesTest(unittest.TestCase): def test_get_module_files_1(self): package = resources.find('data/find_test') modules = set(modutils.get_module_files(package, [])) + expected = ['__init__.py', 'module.py', 'module2.py', 'noendingnewline.py', 'nonregr.py'] self.assertEqual(modules, @@ -254,6 +255,7 @@ class GetModuleFilesTest(unittest.TestCase): """ non_package = resources.find('data/notamodule') modules = modutils.get_module_files(non_package, [], list_all=True) + self.assertEqual( modules, [os.path.join(non_package, 'file.py')], diff --git a/astroid/tests/unittest_nodes.py b/astroid/tests/unittest_nodes.py index aeab26e2..419df968 100644 --- a/astroid/tests/unittest_nodes.py +++ b/astroid/tests/unittest_nodes.py @@ -106,6 +106,7 @@ class AsStringTest(resources.SysPathSetup, unittest.TestCase): with open(resources.find('data/module.py'), 'r') as fobj: self.assertMultiLineEqual(module.as_string(), fobj.read()) + maxDiff = None def test_module2_as_string(self): """check as_string on a whole module prepared to be returned identically """ @@ -491,6 +492,9 @@ class NameNodeTest(unittest.TestCase): class ArgumentsNodeTC(unittest.TestCase): + + @unittest.skipIf(sys.version_info[:2] == (3, 3), + "Line numbering is broken on Python 3.3.") def test_linenumbering(self): ast = builder.parse(''' def func(a, @@ -509,14 +513,6 @@ class ArgumentsNodeTC(unittest.TestCase): self.skipTest('FIXME http://bugs.python.org/issue10445 ' '(no line number on function args)') - def test_builtin_fromlineno_missing(self): - cls = test_utils.extract_node(''' - class Foo(Exception): #@ - pass - ''') - new = cls.getattr('__new__')[-1] - self.assertEqual(new.args.fromlineno, 0) - class UnboundMethodNodeTest(unittest.TestCase): diff --git a/astroid/tests/unittest_python3.py b/astroid/tests/unittest_python3.py index 1dd07c61..3cd7b1f5 100644 --- a/astroid/tests/unittest_python3.py +++ b/astroid/tests/unittest_python3.py @@ -20,6 +20,7 @@ import unittest from astroid import nodes from astroid.tree.node_classes import Assign, Expr, YieldFrom, Name, Const +from astroid import raw_building from astroid.builder import AstroidBuilder from astroid.tree.scoped_nodes import ClassDef, FunctionDef from astroid.test_utils import require_version, extract_node @@ -187,31 +188,31 @@ class Python3TC(unittest.TestCase): pass """)) func = astroid['test'] - self.assertIsInstance(func.args.varargannotation, Name) - self.assertEqual(func.args.varargannotation.name, 'float') - self.assertIsInstance(func.args.kwargannotation, Name) - self.assertEqual(func.args.kwargannotation.name, 'int') + self.assertIsInstance(func.args.vararg.annotation, Name) + self.assertEqual(func.args.vararg.annotation.name, 'float') + self.assertIsInstance(func.args.kwarg.annotation, Name) + self.assertEqual(func.args.kwarg.annotation.name, 'int') self.assertIsInstance(func.returns, Name) self.assertEqual(func.returns.name, 'int') arguments = func.args - self.assertIsInstance(arguments.annotations[0], Name) - self.assertEqual(arguments.annotations[0].name, 'int') - self.assertIsInstance(arguments.annotations[1], Name) - self.assertEqual(arguments.annotations[1].name, 'str') - self.assertIsInstance(arguments.annotations[2], Const) - self.assertIsNone(arguments.annotations[2].value) - self.assertIsNone(arguments.annotations[3]) - self.assertIsNone(arguments.annotations[4]) + self.assertIsInstance(arguments.args[0].annotation, Name) + self.assertEqual(arguments.args[0].annotation.name, 'int') + self.assertIsInstance(arguments.args[1].annotation, Name) + self.assertEqual(arguments.args[1].annotation.name, 'str') + self.assertIsInstance(arguments.args[2].annotation, Const) + self.assertIsNone(arguments.args[2].annotation.value) + self.assertIs(arguments.args[3].annotation, nodes.Empty) + self.assertIs(arguments.args[4].annotation, nodes.Empty) astroid = self.builder.string_build(dedent(""" def test(a: int=1, b: str=2): pass """)) func = astroid['test'] - self.assertIsInstance(func.args.annotations[0], Name) - self.assertEqual(func.args.annotations[0].name, 'int') - self.assertIsInstance(func.args.annotations[1], Name) - self.assertEqual(func.args.annotations[1].name, 'str') + self.assertIsInstance(func.args.args[0].annotation, Name) + self.assertEqual(func.args.args[0].annotation.name, 'int') + self.assertIsInstance(func.args.args[1].annotation, Name) + self.assertEqual(func.args.args[1].annotation.name, 'str') self.assertIsNone(func.returns) @require_version('3.0') @@ -249,6 +250,13 @@ class Python3TC(unittest.TestCase): self.assertIsInstance(value, nodes.Const) self.assertEqual(value.value, expected) + @require_version('3.4') + def test_positional_only_parameters(self): + ast = raw_building.ast_from_object(issubclass) + self.assertEqual(len(ast.args.positional_only), 2) + for name, arg in zip(('cls', 'class_or_tuple'), ast.args.positional_only): + self.assertEqual(arg.name, name) + if __name__ == '__main__': unittest.main() diff --git a/astroid/tests/unittest_regrtest.py b/astroid/tests/unittest_regrtest.py index 9d36befc..21b93dc8 100644 --- a/astroid/tests/unittest_regrtest.py +++ b/astroid/tests/unittest_regrtest.py @@ -24,6 +24,7 @@ import six from astroid import MANAGER, Instance, nodes from astroid.builder import AstroidBuilder from astroid import exceptions +from astroid.interpreter import lookup from astroid.manager import AstroidManager from astroid import raw_building from astroid.test_utils import require_version, extract_node, bootstrap @@ -310,6 +311,13 @@ def test(): with self.assertRaises(AttributeError): node.qname + def test_null_fromlineno_does_not_crash_lookup(self): + node = nodes.ImportFrom('test', [('a', 'a')]) + function = nodes.FunctionDef() + locals_ = {'a': [function]} + lookup._get_locals(node, locals_) + + class Whatever(object): a = property(lambda x: x, lambda x: x) diff --git a/astroid/tests/unittest_scoped_nodes.py b/astroid/tests/unittest_scoped_nodes.py index d9600365..c362f274 100644 --- a/astroid/tests/unittest_scoped_nodes.py +++ b/astroid/tests/unittest_scoped_nodes.py @@ -110,9 +110,23 @@ class ModuleNodeTest(ModuleLoader, unittest.TestCase): self.assertRaises(InferenceError, self.nonregr.igetattr, 'YOAA') def test_wildcard_import_names(self): - m = resources.build_file('data/all.py', 'all') + m = builder.parse(''' + name = 'a' + _bla = 2 + other = 'o' + class Aaa: pass + def func(): print('yo') + __all__ = 'Aaa', '_bla', 'name' + ''') self.assertEqual(m.wildcard_import_names(), ['Aaa', '_bla', 'name']) - m = resources.build_file('data/notall.py', 'notall') + m = builder.parse(''' + name = 'a' + _bla = 2 + other = 'o' + class Aaa: pass + + def func(): return 'yo' + ''') res = sorted(m.wildcard_import_names()) self.assertEqual(res, ['Aaa', 'func', 'name', 'other']) @@ -214,14 +228,14 @@ class ModuleNodeTest(ModuleLoader, unittest.TestCase): self.assertEqual(stream.read().decode(), data) def test_file_stream_physical(self): - path = resources.find('data/all.py') + path = resources.find('data/absimport.py') astroid = builder.AstroidBuilder().file_build(path, 'all') with open(path, 'rb') as file_io: with astroid.stream() as stream: self.assertEqual(stream.read(), file_io.read()) def test_stream_api(self): - path = resources.find('data/all.py') + path = resources.find('data/absimport.py') astroid = builder.AstroidBuilder().file_build(path, 'all') stream = astroid.stream() self.assertTrue(hasattr(stream, 'close')) @@ -284,7 +298,7 @@ class FunctionNodeTest(ModuleLoader, unittest.TestCase): tree = builder.parse(code) func = tree['nested_args'] self.assertEqual(sorted(func.locals), ['a', 'b', 'c', 'd']) - self.assertEqual(func.args.format_args(), 'a, (b, c, d)') + self.assertEqual(func.args.format_args(), 'a, b, c, d') def test_four_args(self): func = self.module['four_args'] diff --git a/astroid/tree/base.py b/astroid/tree/base.py index 43f77d12..58298b8d 100644 --- a/astroid/tree/base.py +++ b/astroid/tree/base.py @@ -226,33 +226,12 @@ class NodeNG(object): """return the previous sibling statement""" return self.parent.previous_sibling() - def nearest(self, nodes): - """return the node which is the nearest before this one in the - given list of nodes - """ - myroot = self.root() - mylineno = self.fromlineno - nearest = None, 0 - for node in nodes: - assert node.root() is myroot, \ - 'nodes %s and %s are not from the same module' % (self, node) - lineno = node.fromlineno - if node.fromlineno > mylineno: - break - if lineno > nearest[1]: - nearest = node, lineno - # FIXME: raise an exception if nearest is None ? - return nearest[0] - # these are lazy because they're relatively expensive to compute for every # single node, and they rarely get looked at @decorators.cachedproperty def fromlineno(self): - if self.lineno is None: - return self._fixed_source_line() - else: - return self.lineno + return self.lineno @decorators.cachedproperty def tolineno(self): @@ -266,29 +245,6 @@ class NodeNG(object): else: return lastchild.tolineno - # TODO / FIXME: - assert self.fromlineno is not None, self - assert self.tolineno is not None, self - - def _fixed_source_line(self): - """return the line number where the given node appears - - we need this method since not all nodes have the lineno attribute - correctly set... - """ - line = self.lineno - _node = self - try: - while line is None: - _node = next(_node.get_children()) - line = _node.lineno - except StopIteration: - _node = self.parent - while _node and line is None: - line = _node.lineno - _node = _node.parent - return line - def block_range(self, lineno): """handle block line numbers range for non block opening statements """ @@ -610,7 +566,6 @@ class LookupMixIn(object): # take care node may be missing lineno information (this is the case for # nodes inserted for living objects) if myframe is frame and mystmt.fromlineno is not None: - assert mystmt.fromlineno is not None, mystmt mylineno = mystmt.fromlineno + offset else: # disabling lineno filtering @@ -620,7 +575,7 @@ class LookupMixIn(object): for node in stmts: stmt = node.statement() # line filtering is on and we have reached our location, break - if mylineno > 0 and stmt.fromlineno > mylineno: + if mylineno > 0 and stmt.fromlineno and stmt.fromlineno > mylineno: break assert hasattr(node, 'assign_type'), (node, node.scope(), node.scope().locals) @@ -678,7 +633,7 @@ class LookupMixIn(object): if not (optional_assign or interpreterutil.are_exclusive(_stmts[pindex], node)): del _stmt_parents[pindex] del _stmts[pindex] - if isinstance(node, treeabc.AssignName): + if isinstance(node, (treeabc.Parameter, treeabc.AssignName)): if not optional_assign and stmt.parent is mystmt.parent: _stmts = [] _stmt_parents = [] diff --git a/astroid/tree/node_classes.py b/astroid/tree/node_classes.py index 78a9afc8..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: @@ -185,25 +174,25 @@ class Arguments(base.AssignTypeMixin, AssignedStmtsMixin, base.NodeNG): @decorators.cachedproperty def fromlineno(self): - lineno = super(Arguments, self).fromlineno - return max(lineno, self.parent.fromlineno or 0) + # Let the Function's lineno be the lineno for this. + if self.parent.fromlineno: + return self.parent.fromlineno + + return super(Arguments, self).fromlineno 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): @@ -211,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): @@ -254,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) @@ -1319,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 diff --git a/astroid/tree/rebuilder.py b/astroid/tree/rebuilder.py index 90a02f73..074aea1e 100644 --- a/astroid/tree/rebuilder.py +++ b/astroid/tree/rebuilder.py @@ -20,6 +20,7 @@ order to get a single Astroid representation """ import ast +import collections import sys import astroid @@ -113,6 +114,53 @@ def _get_context(node): return CONTEXTS.get(type(node.ctx), astroid.Load) +class ParameterVisitor(object): + """A visitor which is used for building the components of Arguments node.""" + + def __init__(self, visitor): + self._visitor = visitor + + def visit(self, param_node, *args): + cls_name = param_node.__class__.__name__ + visit_name = 'visit_' + REDIRECT.get(cls_name, cls_name).lower() + visit_method = getattr(self, visit_name) + return visit_method(param_node, *args) + + def visit_arg(self, param_node, *args): + name = param_node.arg + return self._build_parameter(param_node, name, *args) + + def visit_name(self, param_node, *args): + name = param_node.id + return self._build_parameter(param_node, name, *args) + + def visit_tuple(self, param_node, parent, default): + # We're not supporting nested arguments anymore, but in order to + # simply not crash when running on Python 2, we're unpacking the elements + # before hand. We simply don't want to support this feature anymore, + # so it's possible to be broken. + converted_node = self._visitor.visit(param_node, parent) + for element in converted_node.elts: + param = nodes.Parameter(name=element.name, lineno=param_node.lineno, + col_offset=param_node.col_offset, + parent=parent) + param.postinit(default=default, annotation=nodes.Empty) + yield param + + def _build_parameter(self, param_node, name, parent, default): + param = nodes.Parameter(name=name, lineno=getattr(param_node, 'lineno', None), + col_offset=getattr(param_node, 'col_offset', None), + parent=parent) + annotation = nodes.Empty + param_annotation = getattr(param_node, 'annotation', None) + if param_annotation: + annotation = self._visitor.visit(param_annotation, param) + + param.postinit(default=default, annotation=annotation) + yield param + + + class TreeRebuilder(object): """Rebuilds the ast tree to become an Astroid tree""" @@ -141,57 +189,64 @@ class TreeRebuilder(object): def visit_arguments(self, node, parent): """visit a Arguments node by returning a fresh instance of it""" - vararg, kwarg = node.vararg, node.kwarg - if PY34: - newnode = nodes.Arguments(vararg.arg if vararg else None, - kwarg.arg if kwarg else None, - parent) - else: - newnode = nodes.Arguments(vararg, kwarg, parent) - args = [self.visit(child, newnode) for child in node.args] - defaults = [self.visit(child, newnode) - for child in node.defaults] - varargannotation = None - kwargannotation = None - # change added in 82732 (7c5c678e4164), vararg and kwarg - # are instances of `ast.arg`, not strings - if vararg: - if PY34: - if node.vararg.annotation: - varargannotation = self.visit(node.vararg.annotation, - newnode) - vararg = vararg.arg - elif PY3 and node.varargannotation: - varargannotation = self.visit(node.varargannotation, - newnode) - if kwarg: - if PY34: - if node.kwarg.annotation: - kwargannotation = self.visit(node.kwarg.annotation, - newnode) - kwarg = kwarg.arg - elif PY3: - if node.kwargannotation: - kwargannotation = self.visit(node.kwargannotation, - newnode) - if PY3: - kwonlyargs = [self.visit(child, newnode) for child - in node.kwonlyargs] - kw_defaults = [self.visit(child, newnode) if child else - None for child in node.kw_defaults] - annotations = [self.visit(arg.annotation, newnode) if - arg.annotation else None for arg in node.args] - kwonly_annotations = [self.visit(arg.annotation, newnode) - if arg.annotation else None - for arg in node.kwonlyargs] - else: - kwonlyargs = [] - kw_defaults = [] - annotations = [] - kwonly_annotations = [] - newnode.postinit(args, defaults, kwonlyargs, kw_defaults, - annotations, kwonly_annotations, - varargannotation, kwargannotation) + def _build_variadic(field_name): + param = nodes.Empty + variadic = getattr(node, field_name) + + if variadic: + # Various places to get the name from. + try: + param_name = variadic.id + except AttributeError: + try: + param_name = variadic.arg + except AttributeError: + param_name = variadic + + param = nodes.Parameter(name=param_name, + lineno=newnode.lineno, + col_offset=newnode.col_offset, + parent=newnode) + # Get the annotation of the variadic node. + annotation = nodes.Empty + default = nodes.Empty + variadic_annotation = getattr(variadic, 'annotation', None) + if variadic_annotation is None: + # Support for Python 3.3. + variadic_annotation = getattr(node, field_name + 'annotation', None) + if variadic_annotation: + annotation = self.visit(variadic_annotation, param) + + param.postinit(default=default, annotation=annotation) + return param + + def _build_args(params, defaults): + # Pad the list of defaults so that each arguments gets a default. + defaults = collections.deque(defaults) + while len(defaults) != len(params): + defaults.appendleft(nodes.Empty) + + param_visitor = ParameterVisitor(self) + for parameter in params: + default = defaults.popleft() + if default: + default = self.visit(default, newnode) + + for param in param_visitor.visit(parameter, newnode, default): + yield param + + newnode = nodes.Arguments(parent=parent) + # Build the arguments list. + positional_args = list(_build_args(node.args, node.defaults)) + kwonlyargs = list(_build_args(getattr(node, 'kwonlyargs', ()), + getattr(node, 'kw_defaults', ()))) + # Build vararg and kwarg. + vararg = _build_variadic('vararg') + kwarg = _build_variadic('kwarg') + # Prepare the arguments new node. + newnode.postinit(args=positional_args, vararg=vararg, kwarg=kwarg, + keyword_only=kwonlyargs, + positional_only=[]) return newnode def visit_assert(self, node, parent): @@ -729,11 +784,6 @@ class TreeRebuilder(object): class TreeRebuilder3(TreeRebuilder): """extend and overwrite TreeRebuilder for python3k""" - def visit_arg(self, node, parent): - """visit a arg node by returning a fresh AssName instance""" - # TODO(cpopa): introduce an Arg node instead of using AssignName. - return self.visit_assignname(node, parent, node.arg) - def visit_nameconstant(self, node, parent): # in Python 3.4 we have NameConstant for True / False / None return nodes.NameConstant(node.value, getattr(node, 'lineno', None), diff --git a/astroid/tree/scoped_nodes.py b/astroid/tree/scoped_nodes.py index d04b549b..6744ec82 100644 --- a/astroid/tree/scoped_nodes.py +++ b/astroid/tree/scoped_nodes.py @@ -686,7 +686,7 @@ class CallSite(object): pass # Too many arguments given and no variable arguments. - if len(self.positional_arguments) > len(self._funcnode.args.args): + if len(self.positional_arguments) > len(self._funcnode.args.positional_and_keyword): if not self._funcnode.args.vararg: raise exceptions.InferenceError('Too many positional arguments ' 'passed to {func!r} that does ' @@ -694,10 +694,10 @@ class CallSite(object): call_site=self, func=self._funcnode, arg=name, context=context) - positional = self.positional_arguments[:len(self._funcnode.args.args)] - vararg = self.positional_arguments[len(self._funcnode.args.args):] + positional = self.positional_arguments[:len(self._funcnode.args.positional_and_keyword)] + vararg = self.positional_arguments[len(self._funcnode.args.positional_and_keyword):] argindex = self._funcnode.args.find_argname(name)[0] - kwonlyargs = set(arg.name for arg in self._funcnode.args.kwonlyargs) + kwonlyargs = set(arg.name for arg in self._funcnode.args.keyword_only) kwargs = { key: value for key, value in self.keyword_arguments.items() if key not in kwonlyargs @@ -707,8 +707,8 @@ class CallSite(object): # if the missing positional arguments were passed # as keyword arguments and if so, place them into the # positional args list. - if len(positional) < len(self._funcnode.args.args): - for func_arg in self._funcnode.args.args: + if len(positional) < len(self._funcnode.args.positional_and_keyword): + for func_arg in self._funcnode.args.positional_and_keyword: if func_arg.name in kwargs: arg = kwargs.pop(func_arg.name) positional.append(arg) @@ -748,7 +748,7 @@ class CallSite(object): except IndexError: pass - if self._funcnode.args.kwarg == name: + if self._funcnode.args.kwarg and self._funcnode.args.kwarg.name == name: # It wants all the keywords that were passed into # the call site. if self.has_invalid_keywords(): @@ -769,7 +769,7 @@ class CallSite(object): kwarg.postinit(keys, values) return iter((kwarg, )) - elif self._funcnode.args.vararg == name: + if self._funcnode.args.vararg and self._funcnode.args.vararg.name == name: # It wants all the args that were passed into # the call site. if self.has_invalid_arguments(): @@ -813,7 +813,9 @@ class LambdaFunctionMixin(QualifiedNameMixin, base.FilterStmtsMixin): return CallSite(self, args, keywords) def scope_lookup(self, node, name, offset=0): - if node in self.args.defaults or node in self.args.kw_defaults: + + if node in itertools.chain((self.args.positional_and_keyword, + self.args.keyword_only)): frame = self.parent.frame() # line offset to avoid that def func(f=func) resolve the default # value to the defined function @@ -825,14 +827,16 @@ class LambdaFunctionMixin(QualifiedNameMixin, base.FilterStmtsMixin): def argnames(self): """return a list of argument names""" - if self.args.args: # maybe None with builtin functions - names = _rec_get_names(self.args.args) + if self.args.positional_and_keyword: # maybe None with builtin functions + names = _rec_get_names(self.args.positional_and_keyword) else: names = [] if self.args.vararg: - names.append(self.args.vararg) + names.append(self.args.vararg.name) if self.args.kwarg: - names.append(self.args.kwarg) + names.append(self.args.kwarg.name) + if self.args.keyword_only: + names.extend([arg.name for arg in self.keyword_only]) return names def callable(self): diff --git a/astroid/tree/treeabc.py b/astroid/tree/treeabc.py index 6ad96ba8..5c008255 100644 --- a/astroid/tree/treeabc.py +++ b/astroid/tree/treeabc.py @@ -67,6 +67,10 @@ class Name(NodeNG): """Class representing a Name node""" +class Parameter(NodeNG): + """Class representing a parameter node.""" + + class Arguments(NodeNG): """Class representing an Arguments node""" @@ -339,3 +343,12 @@ class ReservedName(NodeNG): class Unknown(NodeNG): pass + + +class Empty(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. + """ diff --git a/doc/source/conf.py b/doc/source/conf.py index 980fd31e..f4ceb2a8 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -48,9 +48,9 @@ copyright = u'2013, Logilab S.A.' # built documents. # # The short X.Y version. -version = '1.3.4' +from astroid.__pkginfo__ import version # The full version, including alpha/beta/rc tags. -release = '1.3.4' +release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -125,7 +125,7 @@ html_theme = 'default' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff --git a/doc/source/inference.rst b/doc/source/inference.rst index bf67993f..7fed194f 100644 --- a/doc/source/inference.rst +++ b/doc/source/inference.rst @@ -81,7 +81,7 @@ of the :mod:`inference`. .. todo:: actually annotate the doc to structure its approach -.. automodule:: inference +.. automodule:: astroid.inference :members: :undoc-members: .. :special-members: in autodoc/sphinx 1.1 @@ -64,8 +64,8 @@ def install(): include_package_data = True, install_requires = install_requires, packages = find_packages(), - cmdclass={'install_lib': AstroidInstallLib, - 'easy_install': AstroidEasyInstallLib} + cmdclass = {'install_lib': AstroidInstallLib, + 'easy_install': AstroidEasyInstallLib} ) @@ -10,8 +10,8 @@ commands = coverage erase [testenv:coverage-stats] commands = - coverage report --ignore-errors --include="astroid*" - coverage html --ignore-errors --include="astroid*" + coverage report --ignore-errors + coverage html --ignore-errors [testenv] deps = @@ -32,4 +32,4 @@ deps = # Disable warnings because they overflow the Travis log on 3.5 setenv = PYTHONWARNINGS = i # {posargs} allows passing command line arguments to unittest -commands = coverage run --append --branch -m unittest discover {posargs} -s {envsitepackagesdir}/astroid/tests -p "unittest*.py" +commands = coverage run --source astroid --append --branch -m unittest discover {posargs} -s {envsitepackagesdir}/astroid/tests -p "unittest*.py" |