diff -Nru astroid-1.0.1/as_string.py astroid-1.3.8/as_string.py --- astroid-1.0.1/as_string.py 2013-07-29 15:04:24.000000000 +0000 +++ astroid-1.3.8/as_string.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,475 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""This module renders Astroid nodes as string: - -* :func:`to_code` function return equivalent (hopefuly valid) python string - -* :func:`dump` function return an internal representation of nodes found - in the tree, useful for debugging or understanding the tree structure -""" - -import sys - -INDENT = ' ' # 4 spaces ; keep indentation variable - - -def dump(node, ids=False): - """print a nice astroid tree representation. - - :param ids: if true, we also print the ids (usefull for debugging) - """ - result = [] - _repr_tree(node, result, ids=ids) - return "\n".join(result) - -def _repr_tree(node, result, indent='', _done=None, ids=False): - """built a tree representation of a node as a list of lines""" - if _done is None: - _done = set() - if not hasattr(node, '_astroid_fields'): # not a astroid node - return - if node in _done: - result.append( indent + 'loop in tree: %s' % node ) - return - _done.add(node) - node_str = str(node) - if ids: - node_str += ' . \t%x' % id(node) - result.append( indent + node_str ) - indent += INDENT - for field in node._astroid_fields: - value = getattr(node, field) - if isinstance(value, (list, tuple) ): - result.append( indent + field + " = [" ) - for child in value: - if isinstance(child, (list, tuple) ): - # special case for Dict # FIXME - _repr_tree(child[0], result, indent, _done, ids) - _repr_tree(child[1], result, indent, _done, ids) - result.append(indent + ',') - else: - _repr_tree(child, result, indent, _done, ids) - result.append( indent + "]" ) - else: - result.append( indent + field + " = " ) - _repr_tree(value, result, indent, _done, ids) - - -class AsStringVisitor(object): - """Visitor to render an Astroid node as a valid python code string""" - - def __call__(self, node): - """Makes this visitor behave as a simple function""" - return node.accept(self) - - def _stmt_list(self, stmts): - """return a list of nodes to string""" - stmts = '\n'.join([nstr for nstr in [n.accept(self) for n in stmts] if nstr]) - return INDENT + stmts.replace('\n', '\n'+INDENT) - - - ## visit_ methods ########################################### - - def visit_arguments(self, node): - """return an astroid.Function node as string""" - return node.format_args() - - def visit_assattr(self, node): - """return an astroid.AssAttr node as string""" - return self.visit_getattr(node) - - def visit_assert(self, node): - """return an astroid.Assert node as string""" - if node.fail: - return 'assert %s, %s' % (node.test.accept(self), - node.fail.accept(self)) - return 'assert %s' % node.test.accept(self) - - def visit_assname(self, node): - """return an astroid.AssName node as string""" - return node.name - - def visit_assign(self, node): - """return an astroid.Assign node as string""" - lhs = ' = '.join([n.accept(self) for n in node.targets]) - return '%s = %s' % (lhs, node.value.accept(self)) - - def visit_augassign(self, node): - """return an astroid.AugAssign node as string""" - return '%s %s %s' % (node.target.accept(self), node.op, node.value.accept(self)) - - def visit_backquote(self, node): - """return an astroid.Backquote node as string""" - return '`%s`' % node.value.accept(self) - - def visit_binop(self, node): - """return an astroid.BinOp node as string""" - return '(%s) %s (%s)' % (node.left.accept(self), node.op, node.right.accept(self)) - - def visit_boolop(self, node): - """return an astroid.BoolOp node as string""" - return (' %s ' % node.op).join(['(%s)' % n.accept(self) - for n in node.values]) - - def visit_break(self, node): - """return an astroid.Break node as string""" - return 'break' - - def visit_callfunc(self, node): - """return an astroid.CallFunc node as string""" - expr_str = node.func.accept(self) - args = [arg.accept(self) for arg in node.args] - if node.starargs: - args.append( '*' + node.starargs.accept(self)) - if node.kwargs: - args.append( '**' + node.kwargs.accept(self)) - return '%s(%s)' % (expr_str, ', '.join(args)) - - def visit_class(self, node): - """return an astroid.Class node as string""" - decorate = node.decorators and node.decorators.accept(self) or '' - bases = ', '.join([n.accept(self) for n in node.bases]) - bases = bases and '(%s)' % bases or '' - docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' - return '\n\n%sclass %s%s:%s\n%s\n' % (decorate, node.name, bases, docs, - self._stmt_list( node.body)) - - def visit_compare(self, node): - """return an astroid.Compare node as string""" - rhs_str = ' '.join(['%s %s' % (op, expr.accept(self)) - for op, expr in node.ops]) - return '%s %s' % (node.left.accept(self), rhs_str) - - def visit_comprehension(self, node): - """return an astroid.Comprehension node as string""" - ifs = ''.join([ ' if %s' % n.accept(self) for n in node.ifs]) - return 'for %s in %s%s' % (node.target.accept(self), - node.iter.accept(self), ifs ) - - def visit_const(self, node): - """return an astroid.Const node as string""" - return repr(node.value) - - def visit_continue(self, node): - """return an astroid.Continue node as string""" - return 'continue' - - def visit_delete(self, node): # XXX check if correct - """return an astroid.Delete node as string""" - return 'del %s' % ', '.join([child.accept(self) - for child in node.targets]) - - def visit_delattr(self, node): - """return an astroid.DelAttr node as string""" - return self.visit_getattr(node) - - def visit_delname(self, node): - """return an astroid.DelName node as string""" - return node.name - - def visit_decorators(self, node): - """return an astroid.Decorators node as string""" - return '@%s\n' % '\n@'.join([item.accept(self) for item in node.nodes]) - - def visit_dict(self, node): - """return an astroid.Dict node as string""" - return '{%s}' % ', '.join(['%s: %s' % (key.accept(self), - value.accept(self)) for key, value in node.items]) - - def visit_dictcomp(self, node): - """return an astroid.DictComp node as string""" - return '{%s: %s %s}' % (node.key.accept(self), node.value.accept(self), - ' '.join([n.accept(self) for n in node.generators])) - - def visit_discard(self, node): - """return an astroid.Discard node as string""" - return node.value.accept(self) - - def visit_emptynode(self, node): - """dummy method for visiting an Empty node""" - return '' - - def visit_excepthandler(self, node): - if node.type: - if node.name: - excs = 'except %s, %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_ellipsis(self, node): - """return an astroid.Ellipsis node as string""" - return '...' - - def visit_empty(self, node): - """return an Empty node as string""" - return '' - - def visit_exec(self, node): - """return an astroid.Exec node as string""" - if node.locals: - return 'exec %s in %s, %s' % (node.expr.accept(self), - node.locals.accept(self), - node.globals.accept(self)) - if node.globals: - return 'exec %s in %s' % (node.expr.accept(self), - node.globals.accept(self)) - return 'exec %s' % node.expr.accept(self) - - def visit_extslice(self, node): - """return an astroid.ExtSlice node as string""" - return ','.join( [dim.accept(self) for dim in node.dims] ) - - def visit_for(self, node): - """return an astroid.For node as string""" - fors = 'for %s in %s:\n%s' % (node.target.accept(self), - node.iter.accept(self), - self._stmt_list( node.body)) - if node.orelse: - fors = '%s\nelse:\n%s' % (fors, self._stmt_list(node.orelse)) - return fors - - def visit_from(self, node): - """return an astroid.From node as string""" - return 'from %s import %s' % ('.' * (node.level or 0) + node.modname, - _import_string(node.names)) - - def visit_function(self, node): - """return an astroid.Function node as string""" - decorate = node.decorators and node.decorators.accept(self) or '' - docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' - return '\n%sdef %s(%s):%s\n%s' % (decorate, node.name, node.args.accept(self), - docs, self._stmt_list(node.body)) - - def visit_genexpr(self, node): - """return an astroid.GenExpr node as string""" - return '(%s %s)' % (node.elt.accept(self), ' '.join([n.accept(self) - for n in node.generators])) - - def visit_getattr(self, node): - """return an astroid.Getattr node as string""" - return '%s.%s' % (node.expr.accept(self), node.attrname) - - def visit_global(self, node): - """return an astroid.Global node as string""" - return 'global %s' % ', '.join(node.names) - - def visit_if(self, node): - """return an astroid.If node as string""" - ifs = ['if %s:\n%s' % (node.test.accept(self), self._stmt_list(node.body))] - if node.orelse:# XXX use elif ??? - ifs.append('else:\n%s' % self._stmt_list(node.orelse)) - return '\n'.join(ifs) - - def visit_ifexp(self, node): - """return an astroid.IfExp node as string""" - return '%s if %s else %s' % (node.body.accept(self), - node.test.accept(self), node.orelse.accept(self)) - - def visit_import(self, node): - """return an astroid.Import node as string""" - return 'import %s' % _import_string(node.names) - - def visit_keyword(self, node): - """return an astroid.Keyword node as string""" - return '%s=%s' % (node.arg, node.value.accept(self)) - - def visit_lambda(self, node): - """return an astroid.Lambda node as string""" - return 'lambda %s: %s' % (node.args.accept(self), node.body.accept(self)) - - def visit_list(self, node): - """return an astroid.List node as string""" - return '[%s]' % ', '.join([child.accept(self) for child in node.elts]) - - def visit_listcomp(self, node): - """return an astroid.ListComp node as string""" - return '[%s %s]' % (node.elt.accept(self), ' '.join([n.accept(self) - for n in node.generators])) - - def visit_module(self, node): - """return an astroid.Module node as string""" - docs = node.doc and '"""%s"""\n\n' % node.doc or '' - return docs + '\n'.join([n.accept(self) for n in node.body]) + '\n\n' - - def visit_name(self, node): - """return an astroid.Name node as string""" - return node.name - - def visit_pass(self, node): - """return an astroid.Pass node as string""" - return 'pass' - - def visit_print(self, node): - """return an astroid.Print node as string""" - nodes = ', '.join([n.accept(self) for n in node.values]) - if not node.nl: - nodes = '%s,' % nodes - if node.dest: - return 'print >> %s, %s' % (node.dest.accept(self), nodes) - return 'print %s' % nodes - - def visit_raise(self, node): - """return an astroid.Raise node as string""" - if node.exc: - if node.inst: - if node.tback: - return 'raise %s, %s, %s' % (node.exc.accept(self), - node.inst.accept(self), - node.tback.accept(self)) - return 'raise %s, %s' % (node.exc.accept(self), - node.inst.accept(self)) - return 'raise %s' % node.exc.accept(self) - return 'raise' - - def visit_return(self, node): - """return an astroid.Return node as string""" - if node.value: - return 'return %s' % node.value.accept(self) - else: - return 'return' - - def visit_index(self, node): - """return a astroid.Index node as string""" - return node.value.accept(self) - - def visit_set(self, node): - """return an astroid.Set node as string""" - return '{%s}' % ', '.join([child.accept(self) for child in node.elts]) - - def visit_setcomp(self, node): - """return an astroid.SetComp node as string""" - return '{%s %s}' % (node.elt.accept(self), ' '.join([n.accept(self) - for n in node.generators])) - - def visit_slice(self, node): - """return a astroid.Slice node as string""" - lower = node.lower and node.lower.accept(self) or '' - upper = node.upper and node.upper.accept(self) or '' - step = node.step and node.step.accept(self) or '' - if step: - return '%s:%s:%s' % (lower, upper, step) - return '%s:%s' % (lower, upper) - - def visit_subscript(self, node): - """return an astroid.Subscript node as string""" - return '%s[%s]' % (node.value.accept(self), node.slice.accept(self)) - - def visit_tryexcept(self, node): - """return an astroid.TryExcept node as string""" - trys = ['try:\n%s' % self._stmt_list( node.body)] - for handler in node.handlers: - trys.append(handler.accept(self)) - if node.orelse: - trys.append('else:\n%s' % self._stmt_list(node.orelse)) - return '\n'.join(trys) - - def visit_tryfinally(self, node): - """return an astroid.TryFinally node as string""" - return 'try:\n%s\nfinally:\n%s' % (self._stmt_list( node.body), - self._stmt_list(node.finalbody)) - - def visit_tuple(self, node): - """return an astroid.Tuple node as string""" - return '(%s)' % ', '.join([child.accept(self) for child in node.elts]) - - def visit_unaryop(self, node): - """return an astroid.UnaryOp node as string""" - if node.op == 'not': - operator = 'not ' - else: - operator = node.op - return '%s%s' % (operator, node.operand.accept(self)) - - def visit_while(self, node): - """return an astroid.While node as string""" - whiles = 'while %s:\n%s' % (node.test.accept(self), - self._stmt_list(node.body)) - if node.orelse: - whiles = '%s\nelse:\n%s' % (whiles, self._stmt_list(node.orelse)) - return whiles - - def visit_with(self, node): # 'with' without 'as' is possible - """return an astroid.With node as string""" - items = ', '.join(('(%s)' % expr.accept(self)) + - (vars and ' as (%s)' % (vars.accept(self)) or '') - for expr, vars in node.items) - return 'with %s:\n%s' % (items, self._stmt_list( node.body)) - - def visit_yield(self, node): - """yield an ast.Yield node as string""" - yi_val = node.value and (" " + node.value.accept(self)) or "" - expr = 'yield' + yi_val - if node.parent.is_statement: - return expr - else: - return "(%s)" % (expr,) - - -class AsStringVisitor3k(AsStringVisitor): - """AsStringVisitor3k 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) - - def visit_raise(self, node): - """return an astroid.Raise node as string""" - if node.exc: - if node.cause: - return 'raise %s from %s' % (node.exc.accept(self), - node.cause.accept(self)) - return 'raise %s' % node.exc.accept(self) - return 'raise' - - def visit_starred(self, node): - """return Starred node as string""" - return "*" + node.value.accept(self) - - -def _import_string(names): - """return a list of (name, asname) formatted as a string""" - _names = [] - for name, asname in names: - if asname is not None: - _names.append('%s as %s' % (name, asname)) - else: - _names.append(name) - return ', '.join(_names) - - -if sys.version_info >= (3, 0): - AsStringVisitor = AsStringVisitor3k - -# this visitor is stateless, thus it can be reused -to_code = AsStringVisitor() - diff -Nru astroid-1.0.1/astroid/as_string.py astroid-1.3.8/astroid/as_string.py --- astroid-1.0.1/astroid/as_string.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/as_string.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,499 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""This module renders Astroid nodes as string: + +* :func:`to_code` function return equivalent (hopefuly valid) python string + +* :func:`dump` function return an internal representation of nodes found + in the tree, useful for debugging or understanding the tree structure +""" + +import sys + +INDENT = ' ' # 4 spaces ; keep indentation variable + + +def dump(node, ids=False): + """print a nice astroid tree representation. + + :param ids: if true, we also print the ids (usefull for debugging) + """ + result = [] + _repr_tree(node, result, ids=ids) + return "\n".join(result) + +def _repr_tree(node, result, indent='', _done=None, ids=False): + """built a tree representation of a node as a list of lines""" + if _done is None: + _done = set() + if not hasattr(node, '_astroid_fields'): # not a astroid node + return + if node in _done: + result.append(indent + 'loop in tree: %s' % node) + return + _done.add(node) + node_str = str(node) + if ids: + node_str += ' . \t%x' % id(node) + result.append(indent + node_str) + indent += INDENT + for field in node._astroid_fields: + value = getattr(node, field) + if isinstance(value, (list, tuple)): + result.append(indent + field + " = [") + for child in value: + if isinstance(child, (list, tuple)): + # special case for Dict # FIXME + _repr_tree(child[0], result, indent, _done, ids) + _repr_tree(child[1], result, indent, _done, ids) + result.append(indent + ',') + else: + _repr_tree(child, result, indent, _done, ids) + result.append(indent + "]") + else: + result.append(indent + field + " = ") + _repr_tree(value, result, indent, _done, ids) + + +class AsStringVisitor(object): + """Visitor to render an Astroid node as a valid python code string""" + + def __call__(self, node): + """Makes this visitor behave as a simple function""" + return node.accept(self) + + def _stmt_list(self, stmts): + """return a list of nodes to string""" + stmts = '\n'.join([nstr for nstr in [n.accept(self) for n in stmts] if nstr]) + return INDENT + stmts.replace('\n', '\n'+INDENT) + + + ## visit_ methods ########################################### + + def visit_arguments(self, node): + """return an astroid.Function node as string""" + return node.format_args() + + def visit_assattr(self, node): + """return an astroid.AssAttr node as string""" + return self.visit_getattr(node) + + def visit_assert(self, node): + """return an astroid.Assert node as string""" + if node.fail: + return 'assert %s, %s' % (node.test.accept(self), + node.fail.accept(self)) + return 'assert %s' % node.test.accept(self) + + def visit_assname(self, node): + """return an astroid.AssName node as string""" + return node.name + + def visit_assign(self, node): + """return an astroid.Assign node as string""" + lhs = ' = '.join([n.accept(self) for n in node.targets]) + return '%s = %s' % (lhs, node.value.accept(self)) + + def visit_augassign(self, node): + """return an astroid.AugAssign node as string""" + return '%s %s %s' % (node.target.accept(self), node.op, node.value.accept(self)) + + def visit_backquote(self, node): + """return an astroid.Backquote node as string""" + return '`%s`' % node.value.accept(self) + + def visit_binop(self, node): + """return an astroid.BinOp node as string""" + return '(%s) %s (%s)' % (node.left.accept(self), node.op, node.right.accept(self)) + + def visit_boolop(self, node): + """return an astroid.BoolOp node as string""" + return (' %s ' % node.op).join(['(%s)' % n.accept(self) + for n in node.values]) + + def visit_break(self, node): + """return an astroid.Break node as string""" + return 'break' + + def visit_callfunc(self, node): + """return an astroid.CallFunc node as string""" + expr_str = node.func.accept(self) + args = [arg.accept(self) for arg in node.args] + if node.starargs: + args.append('*' + node.starargs.accept(self)) + if node.kwargs: + args.append('**' + node.kwargs.accept(self)) + return '%s(%s)' % (expr_str, ', '.join(args)) + + def visit_class(self, node): + """return an astroid.Class node as string""" + decorate = node.decorators and node.decorators.accept(self) or '' + bases = ', '.join([n.accept(self) for n in node.bases]) + if sys.version_info[0] == 2: + bases = bases and '(%s)' % bases or '' + else: + metaclass = node.metaclass() + if metaclass and not node.has_metaclass_hack(): + if bases: + bases = '(%s, metaclass=%s)' % (bases, metaclass.name) + else: + bases = '(metaclass=%s)' % metaclass.name + else: + bases = bases and '(%s)' % bases or '' + docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' + return '\n\n%sclass %s%s:%s\n%s\n' % (decorate, node.name, bases, docs, + self._stmt_list(node.body)) + + def visit_compare(self, node): + """return an astroid.Compare node as string""" + rhs_str = ' '.join(['%s %s' % (op, expr.accept(self)) + for op, expr in node.ops]) + return '%s %s' % (node.left.accept(self), rhs_str) + + def visit_comprehension(self, node): + """return an astroid.Comprehension node as string""" + ifs = ''.join([' if %s' % n.accept(self) for n in node.ifs]) + return 'for %s in %s%s' % (node.target.accept(self), + node.iter.accept(self), ifs) + + def visit_const(self, node): + """return an astroid.Const node as string""" + return repr(node.value) + + def visit_continue(self, node): + """return an astroid.Continue node as string""" + return 'continue' + + def visit_delete(self, node): # XXX check if correct + """return an astroid.Delete node as string""" + return 'del %s' % ', '.join([child.accept(self) + for child in node.targets]) + + def visit_delattr(self, node): + """return an astroid.DelAttr node as string""" + return self.visit_getattr(node) + + def visit_delname(self, node): + """return an astroid.DelName node as string""" + return node.name + + def visit_decorators(self, node): + """return an astroid.Decorators node as string""" + return '@%s\n' % '\n@'.join([item.accept(self) for item in node.nodes]) + + def visit_dict(self, node): + """return an astroid.Dict node as string""" + return '{%s}' % ', '.join(['%s: %s' % (key.accept(self), + value.accept(self)) + for key, value in node.items]) + + def visit_dictcomp(self, node): + """return an astroid.DictComp node as string""" + return '{%s: %s %s}' % (node.key.accept(self), node.value.accept(self), + ' '.join([n.accept(self) for n in node.generators])) + + def visit_discard(self, node): + """return an astroid.Discard node as string""" + return node.value.accept(self) + + def visit_emptynode(self, node): + """dummy method for visiting an Empty node""" + return '' + + def visit_excepthandler(self, node): + if node.type: + if node.name: + excs = 'except %s, %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_ellipsis(self, node): + """return an astroid.Ellipsis node as string""" + return '...' + + def visit_empty(self, node): + """return an Empty node as string""" + return '' + + def visit_exec(self, node): + """return an astroid.Exec node as string""" + if node.locals: + return 'exec %s in %s, %s' % (node.expr.accept(self), + node.locals.accept(self), + node.globals.accept(self)) + if node.globals: + return 'exec %s in %s' % (node.expr.accept(self), + node.globals.accept(self)) + return 'exec %s' % node.expr.accept(self) + + def visit_extslice(self, node): + """return an astroid.ExtSlice node as string""" + return ','.join([dim.accept(self) for dim in node.dims]) + + def visit_for(self, node): + """return an astroid.For node as string""" + fors = 'for %s in %s:\n%s' % (node.target.accept(self), + node.iter.accept(self), + self._stmt_list(node.body)) + if node.orelse: + fors = '%s\nelse:\n%s' % (fors, self._stmt_list(node.orelse)) + return fors + + def visit_from(self, node): + """return an astroid.From node as string""" + return 'from %s import %s' % ('.' * (node.level or 0) + node.modname, + _import_string(node.names)) + + def visit_function(self, node): + """return an astroid.Function node as string""" + decorate = node.decorators and node.decorators.accept(self) or '' + docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' + return '\n%sdef %s(%s):%s\n%s' % (decorate, node.name, node.args.accept(self), + docs, self._stmt_list(node.body)) + + def visit_genexpr(self, node): + """return an astroid.GenExpr node as string""" + return '(%s %s)' % (node.elt.accept(self), + ' '.join([n.accept(self) for n in node.generators])) + + def visit_getattr(self, node): + """return an astroid.Getattr node as string""" + return '%s.%s' % (node.expr.accept(self), node.attrname) + + def visit_global(self, node): + """return an astroid.Global node as string""" + return 'global %s' % ', '.join(node.names) + + def visit_if(self, node): + """return an astroid.If node as string""" + ifs = ['if %s:\n%s' % (node.test.accept(self), self._stmt_list(node.body))] + if node.orelse:# XXX use elif ??? + ifs.append('else:\n%s' % self._stmt_list(node.orelse)) + return '\n'.join(ifs) + + def visit_ifexp(self, node): + """return an astroid.IfExp node as string""" + return '%s if %s else %s' % (node.body.accept(self), + node.test.accept(self), + node.orelse.accept(self)) + + def visit_import(self, node): + """return an astroid.Import node as string""" + return 'import %s' % _import_string(node.names) + + def visit_keyword(self, node): + """return an astroid.Keyword node as string""" + return '%s=%s' % (node.arg, node.value.accept(self)) + + def visit_lambda(self, node): + """return an astroid.Lambda node as string""" + return 'lambda %s: %s' % (node.args.accept(self), + node.body.accept(self)) + + def visit_list(self, node): + """return an astroid.List node as string""" + return '[%s]' % ', '.join([child.accept(self) for child in node.elts]) + + def visit_listcomp(self, node): + """return an astroid.ListComp node as string""" + return '[%s %s]' % (node.elt.accept(self), + ' '.join([n.accept(self) for n in node.generators])) + + def visit_module(self, node): + """return an astroid.Module node as string""" + docs = node.doc and '"""%s"""\n\n' % node.doc or '' + return docs + '\n'.join([n.accept(self) for n in node.body]) + '\n\n' + + def visit_name(self, node): + """return an astroid.Name node as string""" + return node.name + + def visit_pass(self, node): + """return an astroid.Pass node as string""" + return 'pass' + + def visit_print(self, node): + """return an astroid.Print node as string""" + nodes = ', '.join([n.accept(self) for n in node.values]) + if not node.nl: + nodes = '%s,' % nodes + if node.dest: + return 'print >> %s, %s' % (node.dest.accept(self), nodes) + return 'print %s' % nodes + + def visit_raise(self, node): + """return an astroid.Raise node as string""" + if node.exc: + if node.inst: + if node.tback: + return 'raise %s, %s, %s' % (node.exc.accept(self), + node.inst.accept(self), + node.tback.accept(self)) + return 'raise %s, %s' % (node.exc.accept(self), + node.inst.accept(self)) + return 'raise %s' % node.exc.accept(self) + return 'raise' + + def visit_return(self, node): + """return an astroid.Return node as string""" + if node.value: + return 'return %s' % node.value.accept(self) + else: + return 'return' + + def visit_index(self, node): + """return a astroid.Index node as string""" + return node.value.accept(self) + + def visit_set(self, node): + """return an astroid.Set node as string""" + return '{%s}' % ', '.join([child.accept(self) for child in node.elts]) + + def visit_setcomp(self, node): + """return an astroid.SetComp node as string""" + return '{%s %s}' % (node.elt.accept(self), + ' '.join([n.accept(self) for n in node.generators])) + + def visit_slice(self, node): + """return a astroid.Slice node as string""" + lower = node.lower and node.lower.accept(self) or '' + upper = node.upper and node.upper.accept(self) or '' + step = node.step and node.step.accept(self) or '' + if step: + return '%s:%s:%s' % (lower, upper, step) + return '%s:%s' % (lower, upper) + + def visit_subscript(self, node): + """return an astroid.Subscript node as string""" + return '%s[%s]' % (node.value.accept(self), node.slice.accept(self)) + + def visit_tryexcept(self, node): + """return an astroid.TryExcept node as string""" + trys = ['try:\n%s' % self._stmt_list(node.body)] + for handler in node.handlers: + trys.append(handler.accept(self)) + if node.orelse: + trys.append('else:\n%s' % self._stmt_list(node.orelse)) + return '\n'.join(trys) + + def visit_tryfinally(self, node): + """return an astroid.TryFinally node as string""" + return 'try:\n%s\nfinally:\n%s' % (self._stmt_list(node.body), + self._stmt_list(node.finalbody)) + + def visit_tuple(self, node): + """return an astroid.Tuple node as string""" + if len(node.elts) == 1: + return '(%s, )' % node.elts[0].accept(self) + return '(%s)' % ', '.join([child.accept(self) for child in node.elts]) + + def visit_unaryop(self, node): + """return an astroid.UnaryOp node as string""" + if node.op == 'not': + operator = 'not ' + else: + operator = node.op + return '%s%s' % (operator, node.operand.accept(self)) + + def visit_while(self, node): + """return an astroid.While node as string""" + whiles = 'while %s:\n%s' % (node.test.accept(self), + self._stmt_list(node.body)) + if node.orelse: + whiles = '%s\nelse:\n%s' % (whiles, self._stmt_list(node.orelse)) + return whiles + + def visit_with(self, node): # 'with' without 'as' is possible + """return an astroid.With node as string""" + items = ', '.join(('(%s)' % expr.accept(self)) + + (vars and ' as (%s)' % (vars.accept(self)) or '') + for expr, vars in node.items) + return 'with %s:\n%s' % (items, self._stmt_list(node.body)) + + def visit_yield(self, node): + """yield an ast.Yield node as string""" + yi_val = node.value and (" " + node.value.accept(self)) or "" + expr = 'yield' + yi_val + if node.parent.is_statement: + return expr + else: + return "(%s)" % (expr,) + + +class AsStringVisitor3k(AsStringVisitor): + """AsStringVisitor3k 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) + + def visit_raise(self, node): + """return an astroid.Raise node as string""" + if node.exc: + if node.cause: + return 'raise %s from %s' % (node.exc.accept(self), + node.cause.accept(self)) + return 'raise %s' % node.exc.accept(self) + return 'raise' + + def visit_starred(self, node): + """return Starred node as string""" + return "*" + node.value.accept(self) + + def visit_yieldfrom(self, node): + """ Return an astroid.YieldFrom node as string. """ + yi_val = node.value and (" " + node.value.accept(self)) or "" + expr = 'yield from' + yi_val + if node.parent.is_statement: + return expr + else: + return "(%s)" % (expr,) + + +def _import_string(names): + """return a list of (name, asname) formatted as a string""" + _names = [] + for name, asname in names: + if asname is not None: + _names.append('%s as %s' % (name, asname)) + else: + _names.append(name) + return ', '.join(_names) + + +if sys.version_info >= (3, 0): + AsStringVisitor = AsStringVisitor3k + +# this visitor is stateless, thus it can be reused +to_code = AsStringVisitor() + diff -Nru astroid-1.0.1/astroid/astpeephole.py astroid-1.3.8/astroid/astpeephole.py --- astroid-1.0.1/astroid/astpeephole.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/astpeephole.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,86 @@ +# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""Small AST optimizations.""" + +import _ast + +from astroid import nodes + + +__all__ = ('ASTPeepholeOptimizer', ) + + +try: + _TYPES = (_ast.Str, _ast.Bytes) +except AttributeError: + _TYPES = (_ast.Str, ) + + +class ASTPeepholeOptimizer(object): + """Class for applying small optimizations to generate new AST.""" + + def optimize_binop(self, node): + """Optimize BinOps with string Const nodes on the lhs. + + This fixes an infinite recursion crash, where multiple + strings are joined using the addition operator. With a + sufficient number of such strings, astroid will fail + with a maximum recursion limit exceeded. The + function will return a Const node with all the strings + already joined. + Return ``None`` if no AST node can be obtained + through optimization. + """ + ast_nodes = [] + current = node + while isinstance(current, _ast.BinOp): + # lhs must be a BinOp with the addition operand. + if not isinstance(current.left, _ast.BinOp): + return + if (not isinstance(current.left.op, _ast.Add) + or not isinstance(current.op, _ast.Add)): + return + + # rhs must a str / bytes. + if not isinstance(current.right, _TYPES): + return + + ast_nodes.append(current.right.s) + current = current.left + + if (isinstance(current, _ast.BinOp) + and isinstance(current.left, _TYPES) + and isinstance(current.right, _TYPES)): + # Stop early if we are at the last BinOp in + # the operation + ast_nodes.append(current.right.s) + ast_nodes.append(current.left.s) + break + + if not ast_nodes: + return + + # If we have inconsistent types, bail out. + known = type(ast_nodes[0]) + if any(type(element) is not known + for element in ast_nodes[1:]): + return + + value = known().join(reversed(ast_nodes)) + newnode = nodes.Const(value) + return newnode diff -Nru astroid-1.0.1/astroid/bases.py astroid-1.3.8/astroid/bases.py --- astroid-1.0.1/astroid/bases.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/bases.py 2015-08-02 19:35:55.000000000 +0000 @@ -0,0 +1,652 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""This module contains base classes and functions for the nodes and some +inference utils. +""" + +__docformat__ = "restructuredtext en" + +import sys +from contextlib import contextmanager + +from logilab.common.decorators import cachedproperty + +from astroid.exceptions import (InferenceError, AstroidError, NotFoundError, + UnresolvableName, UseInferenceDefault) + + +if sys.version_info >= (3, 0): + BUILTINS = 'builtins' +else: + BUILTINS = '__builtin__' + + +class Proxy(object): + """a simple proxy object""" + + _proxied = None # proxied object may be set by class or by instance + + def __init__(self, proxied=None): + if proxied is not None: + self._proxied = proxied + + def __getattr__(self, name): + if name == '_proxied': + return getattr(self.__class__, '_proxied') + if name in self.__dict__: + return self.__dict__[name] + return getattr(self._proxied, name) + + def infer(self, context=None): + yield self + + +# Inference ################################################################## + +class InferenceContext(object): + __slots__ = ('path', 'lookupname', 'callcontext', 'boundnode', 'infered') + + def __init__(self, path=None, infered=None): + self.path = path or set() + self.lookupname = None + self.callcontext = None + self.boundnode = None + self.infered = infered or {} + + def push(self, node): + name = self.lookupname + if (node, name) in self.path: + raise StopIteration() + self.path.add((node, name)) + + def clone(self): + # XXX copy lookupname/callcontext ? + clone = InferenceContext(self.path, infered=self.infered) + clone.callcontext = self.callcontext + clone.boundnode = self.boundnode + return clone + + def cache_generator(self, key, generator): + results = [] + for result in generator: + results.append(result) + yield result + + self.infered[key] = tuple(results) + return + + @contextmanager + def restore_path(self): + path = set(self.path) + yield + self.path = path + +def copy_context(context): + if context is not None: + return context.clone() + else: + return InferenceContext() + + +def _infer_stmts(stmts, context, frame=None): + """return an iterator on statements inferred by each statement in + """ + stmt = None + infered = False + if context is not None: + name = context.lookupname + context = context.clone() + else: + name = None + context = InferenceContext() + for stmt in stmts: + if stmt is YES: + yield stmt + infered = True + continue + context.lookupname = stmt._infer_name(frame, name) + try: + for infered in stmt.infer(context): + yield infered + infered = True + except UnresolvableName: + continue + except InferenceError: + yield YES + infered = True + if not infered: + raise InferenceError(str(stmt)) + + +# special inference objects (e.g. may be returned as nodes by .infer()) ####### + +class _Yes(object): + """a yes object""" + def __repr__(self): + return 'YES' + def __getattribute__(self, name): + if name == 'next': + raise AttributeError('next method should not be called') + if name.startswith('__') and name.endswith('__'): + # to avoid inspection pb + return super(_Yes, self).__getattribute__(name) + return self + def __call__(self, *args, **kwargs): + return self + + +YES = _Yes() + + +class Instance(Proxy): + """a special node representing a class instance""" + def getattr(self, name, context=None, lookupclass=True): + try: + values = self._proxied.instance_attr(name, context) + except NotFoundError: + if name == '__class__': + return [self._proxied] + if lookupclass: + # class attributes not available through the instance + # unless they are explicitly defined + if name in ('__name__', '__bases__', '__mro__', '__subclasses__'): + return self._proxied.local_attr(name) + return self._proxied.getattr(name, context) + raise NotFoundError(name) + # since we've no context information, return matching class members as + # well + if lookupclass: + try: + return values + self._proxied.getattr(name, context) + except NotFoundError: + pass + return values + + def igetattr(self, name, context=None): + """inferred getattr""" + if not context: + context = InferenceContext() + try: + # avoid recursively inferring the same attr on the same class + + context.push((self._proxied, name)) + # XXX frame should be self._proxied, or not ? + get_attr = self.getattr(name, context, lookupclass=False) + return _infer_stmts( + self._wrap_attr(get_attr, context), + context, + frame=self, + ) + except NotFoundError: + try: + # fallback to class'igetattr since it has some logic to handle + # descriptors + return self._wrap_attr(self._proxied.igetattr(name, context), + context) + except NotFoundError: + raise InferenceError(name) + + def _wrap_attr(self, attrs, context=None): + """wrap bound methods of attrs in a InstanceMethod proxies""" + for attr in attrs: + if isinstance(attr, UnboundMethod): + if BUILTINS + '.property' in attr.decoratornames(): + for infered in attr.infer_call_result(self, context): + yield infered + else: + yield BoundMethod(attr, self) + else: + yield attr + + def infer_call_result(self, caller, context=None): + """infer what a class instance is returning when called""" + infered = False + for node in self._proxied.igetattr('__call__', context): + if node is YES: + continue + for res in node.infer_call_result(caller, context): + infered = True + yield res + if not infered: + raise InferenceError() + + def __repr__(self): + return '' % (self._proxied.root().name, + self._proxied.name, + id(self)) + def __str__(self): + return 'Instance of %s.%s' % (self._proxied.root().name, + self._proxied.name) + + def callable(self): + try: + self._proxied.getattr('__call__') + return True + except NotFoundError: + return False + + def pytype(self): + return self._proxied.qname() + + def display_type(self): + return 'Instance of' + + +class UnboundMethod(Proxy): + """a special node representing a method not bound to an instance""" + def __repr__(self): + frame = self._proxied.parent.frame() + return '<%s %s of %s at 0x%s' % (self.__class__.__name__, + self._proxied.name, + frame.qname(), id(self)) + + def is_bound(self): + return False + + def getattr(self, name, context=None): + if name == 'im_func': + return [self._proxied] + return super(UnboundMethod, self).getattr(name, context) + + def igetattr(self, name, context=None): + if name == 'im_func': + return iter((self._proxied,)) + return super(UnboundMethod, self).igetattr(name, context) + + def infer_call_result(self, caller, context): + # If we're unbound method __new__ of builtin object, the result is an + # instance of the class given as first argument. + if (self._proxied.name == '__new__' and + self._proxied.parent.frame().qname() == '%s.object' % BUILTINS): + infer = caller.args[0].infer() if caller.args else [] + return ((x is YES and x or Instance(x)) for x in infer) + return self._proxied.infer_call_result(caller, context) + + +class BoundMethod(UnboundMethod): + """a special node representing a method bound to an instance""" + def __init__(self, proxy, bound): + UnboundMethod.__init__(self, proxy) + self.bound = bound + + def is_bound(self): + return True + + def infer_call_result(self, caller, context): + context = context.clone() + context.boundnode = self.bound + return self._proxied.infer_call_result(caller, context) + + +class Generator(Instance): + """a special node representing a generator. + + Proxied class is set once for all in raw_building. + """ + def callable(self): + return False + + def pytype(self): + return '%s.generator' % BUILTINS + + def display_type(self): + return 'Generator' + + def __repr__(self): + return '' % (self._proxied.name, self.lineno, id(self)) + + def __str__(self): + return 'Generator(%s)' % (self._proxied.name) + + +# decorators ################################################################## + +def path_wrapper(func): + """return the given infer function wrapped to handle the path""" + def wrapped(node, context=None, _func=func, **kwargs): + """wrapper function handling context""" + if context is None: + context = InferenceContext() + context.push(node) + yielded = set() + for res in _func(node, context, **kwargs): + # unproxy only true instance, not const, tuple, dict... + if res.__class__ is Instance: + ares = res._proxied + else: + ares = res + if not ares in yielded: + yield res + yielded.add(ares) + return wrapped + +def yes_if_nothing_infered(func): + def wrapper(*args, **kwargs): + infered = False + for node in func(*args, **kwargs): + infered = True + yield node + if not infered: + yield YES + return wrapper + +def raise_if_nothing_infered(func): + def wrapper(*args, **kwargs): + infered = False + for node in func(*args, **kwargs): + infered = True + yield node + if not infered: + raise InferenceError() + return wrapper + + +# Node ###################################################################### + +class NodeNG(object): + """Base Class for all Astroid node classes. + + It represents a node of the new abstract syntax tree. + """ + is_statement = False + optional_assign = False # True for For (and for Comprehension if py <3.0) + is_function = False # True for Function nodes + # attributes below are set by the builder module or by raw factories + lineno = None + fromlineno = None + tolineno = None + col_offset = None + # parent node in the tree + parent = None + # attributes containing child node(s) redefined in most concrete classes: + _astroid_fields = () + # instance specific inference function infer(node, context) + _explicit_inference = None + + def infer(self, context=None, **kwargs): + """main interface to the interface system, return a generator on infered + values. + + If the instance has some explicit inference function set, it will be + called instead of the default interface. + """ + if self._explicit_inference is not None: + # explicit_inference is not bound, give it self explicitly + try: + return self._explicit_inference(self, context, **kwargs) + except UseInferenceDefault: + pass + + if not context: + return self._infer(context, **kwargs) + + key = (self, context.lookupname, + context.callcontext, context.boundnode) + if key in context.infered: + return iter(context.infered[key]) + + return context.cache_generator(key, self._infer(context, **kwargs)) + + def _repr_name(self): + """return self.name or self.attrname or '' for nice representation""" + return getattr(self, 'name', getattr(self, 'attrname', '')) + + def __str__(self): + return '%s(%s)' % (self.__class__.__name__, self._repr_name()) + + def __repr__(self): + return '<%s(%s) l.%s [%s] at 0x%x>' % (self.__class__.__name__, + self._repr_name(), + self.fromlineno, + self.root().name, + id(self)) + + + def accept(self, visitor): + func = getattr(visitor, "visit_" + self.__class__.__name__.lower()) + return func(self) + + def get_children(self): + for field in self._astroid_fields: + attr = getattr(self, field) + if attr is None: + continue + if isinstance(attr, (list, tuple)): + for elt in attr: + yield elt + else: + yield attr + + def last_child(self): + """an optimized version of list(get_children())[-1]""" + for field in self._astroid_fields[::-1]: + attr = getattr(self, field) + if not attr: # None or empty listy / tuple + continue + if attr.__class__ in (list, tuple): + return attr[-1] + else: + return attr + return None + + def parent_of(self, node): + """return true if i'm a parent of the given node""" + parent = node.parent + while parent is not None: + if self is parent: + return True + parent = parent.parent + return False + + def statement(self): + """return the first parent node marked as statement node""" + if self.is_statement: + return self + return self.parent.statement() + + def frame(self): + """return the first parent frame node (i.e. Module, Function or Class) + """ + return self.parent.frame() + + def scope(self): + """return the first node defining a new scope (i.e. Module, Function, + Class, Lambda but also GenExpr) + """ + return self.parent.scope() + + def root(self): + """return the root node of the tree, (i.e. a Module)""" + if self.parent: + return self.parent.root() + return self + + def child_sequence(self, child): + """search for the right sequence where the child lies in""" + for field in self._astroid_fields: + node_or_sequence = getattr(self, field) + if node_or_sequence is child: + return [node_or_sequence] + # /!\ compiler.ast Nodes have an __iter__ walking over child nodes + if isinstance(node_or_sequence, (tuple, list)) and child in node_or_sequence: + return node_or_sequence + else: + msg = 'Could not find %s in %s\'s children' + raise AstroidError(msg % (repr(child), repr(self))) + + def locate_child(self, child): + """return a 2-uple (child attribute name, sequence or node)""" + for field in self._astroid_fields: + node_or_sequence = getattr(self, field) + # /!\ compiler.ast Nodes have an __iter__ walking over child nodes + if child is node_or_sequence: + return field, child + if isinstance(node_or_sequence, (tuple, list)) and child in node_or_sequence: + return field, node_or_sequence + msg = 'Could not find %s in %s\'s children' + raise AstroidError(msg % (repr(child), repr(self))) + # FIXME : should we merge child_sequence and locate_child ? locate_child + # is only used in are_exclusive, child_sequence one time in pylint. + + def next_sibling(self): + """return the next sibling statement""" + return self.parent.next_sibling() + + def previous_sibling(self): + """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 + + @cachedproperty + def fromlineno(self): + if self.lineno is None: + return self._fixed_source_line() + else: + return self.lineno + + @cachedproperty + def tolineno(self): + if not self._astroid_fields: + # can't have children + lastchild = None + else: + lastchild = self.last_child() + if lastchild is None: + return self.fromlineno + 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 + """ + return lineno, self.tolineno + + def set_local(self, name, stmt): + """delegate to a scoped parent handling a locals dictionary""" + self.parent.set_local(name, stmt) + + def nodes_of_class(self, klass, skip_klass=None): + """return an iterator on nodes which are instance of the given class(es) + + klass may be a class object or a tuple of class objects + """ + if isinstance(self, klass): + yield self + for child_node in self.get_children(): + if skip_klass is not None and isinstance(child_node, skip_klass): + continue + for matching in child_node.nodes_of_class(klass, skip_klass): + yield matching + + def _infer_name(self, frame, name): + # overridden for From, Import, Global, TryExcept and Arguments + return None + + def _infer(self, context=None): + """we don't know how to resolve a statement by default""" + # this method is overridden by most concrete classes + raise InferenceError(self.__class__.__name__) + + def infered(self): + '''return list of infered values for a more simple inference usage''' + return list(self.infer()) + + def instanciate_class(self): + """instanciate a node if it is a Class node, else return self""" + return self + + def has_base(self, node): + return False + + def callable(self): + return False + + def eq(self, value): + return False + + def as_string(self): + from astroid.as_string import to_code + return to_code(self) + + def repr_tree(self, ids=False): + from astroid.as_string import dump + return dump(self) + + +class Statement(NodeNG): + """Statement node adding a few attributes""" + is_statement = True + + def next_sibling(self): + """return the next sibling statement""" + stmts = self.parent.child_sequence(self) + index = stmts.index(self) + try: + return stmts[index +1] + except IndexError: + pass + + def previous_sibling(self): + """return the previous sibling statement""" + stmts = self.parent.child_sequence(self) + index = stmts.index(self) + if index >= 1: + return stmts[index -1] diff -Nru astroid-1.0.1/astroid/brain/builtin_inference.py astroid-1.3.8/astroid/brain/builtin_inference.py --- astroid-1.0.1/astroid/brain/builtin_inference.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/brain/builtin_inference.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,245 @@ +"""Astroid hooks for various builtins.""" + +import sys +from functools import partial +from textwrap import dedent + +import six +from astroid import (MANAGER, UseInferenceDefault, + inference_tip, YES, InferenceError, UnresolvableName) +from astroid import nodes +from astroid.builder import AstroidBuilder + + +def _extend_str(class_node, rvalue): + """function to extend builtin str/unicode class""" + # TODO(cpopa): this approach will make astroid to believe + # that some arguments can be passed by keyword, but + # unfortunately, strings and bytes don't accept keyword arguments. + code = dedent(''' + class whatever(object): + def join(self, iterable): + return {rvalue} + def replace(self, old, new, count=None): + return {rvalue} + def format(self, *args, **kwargs): + return {rvalue} + def encode(self, encoding='ascii', errors=None): + return '' + def decode(self, encoding='ascii', errors=None): + return u'' + def capitalize(self): + return {rvalue} + def title(self): + return {rvalue} + def lower(self): + return {rvalue} + def upper(self): + return {rvalue} + def swapcase(self): + return {rvalue} + def index(self, sub, start=None, end=None): + return 0 + def find(self, sub, start=None, end=None): + return 0 + def count(self, sub, start=None, end=None): + return 0 + def strip(self, chars=None): + return {rvalue} + def lstrip(self, chars=None): + return {rvalue} + def rstrip(self, chars=None): + return {rvalue} + def rjust(self, width, fillchar=None): + return {rvalue} + def center(self, width, fillchar=None): + return {rvalue} + def ljust(self, width, fillchar=None): + return {rvalue} + ''') + code = code.format(rvalue=rvalue) + fake = AstroidBuilder(MANAGER).string_build(code)['whatever'] + for method in fake.mymethods(): + class_node.locals[method.name] = [method] + method.parent = class_node + +def extend_builtins(class_transforms): + from astroid.bases import BUILTINS + builtin_ast = MANAGER.astroid_cache[BUILTINS] + for class_name, transform in class_transforms.items(): + transform(builtin_ast[class_name]) + +if sys.version_info > (3, 0): + extend_builtins({'bytes': partial(_extend_str, rvalue="b''"), + 'str': partial(_extend_str, rvalue="''")}) +else: + extend_builtins({'str': partial(_extend_str, rvalue="''"), + 'unicode': partial(_extend_str, rvalue="u''")}) + + +def register_builtin_transform(transform, builtin_name): + """Register a new transform function for the given *builtin_name*. + + The transform function must accept two parameters, a node and + an optional context. + """ + def _transform_wrapper(node, context=None): + result = transform(node, context=context) + if result: + result.parent = node + result.lineno = node.lineno + result.col_offset = node.col_offset + return iter([result]) + + MANAGER.register_transform(nodes.CallFunc, + inference_tip(_transform_wrapper), + lambda n: (isinstance(n.func, nodes.Name) and + n.func.name == builtin_name)) + + +def _generic_inference(node, context, node_type, transform): + args = node.args + if not args: + return node_type() + if len(node.args) > 1: + raise UseInferenceDefault() + + arg, = args + transformed = transform(arg) + if not transformed: + try: + infered = next(arg.infer(context=context)) + except (InferenceError, StopIteration): + raise UseInferenceDefault() + if infered is YES: + raise UseInferenceDefault() + transformed = transform(infered) + if not transformed or transformed is YES: + raise UseInferenceDefault() + return transformed + + +def _generic_transform(arg, klass, iterables, build_elts): + if isinstance(arg, klass): + return arg + elif isinstance(arg, iterables): + if not all(isinstance(elt, nodes.Const) + for elt in arg.elts): + # TODO(cpopa): Don't support heterogenous elements. + # Not yet, though. + raise UseInferenceDefault() + elts = [elt.value for elt in arg.elts] + elif isinstance(arg, nodes.Dict): + if not all(isinstance(elt[0], nodes.Const) + for elt in arg.items): + raise UseInferenceDefault() + elts = [item[0].value for item in arg.items] + elif (isinstance(arg, nodes.Const) and + isinstance(arg.value, (six.string_types, six.binary_type))): + elts = arg.value + else: + return + return klass(elts=build_elts(elts)) + + +def _infer_builtin(node, context, + klass=None, iterables=None, + build_elts=None): + transform_func = partial( + _generic_transform, + klass=klass, + iterables=iterables, + build_elts=build_elts) + + return _generic_inference(node, context, klass, transform_func) + +# pylint: disable=invalid-name +infer_tuple = partial( + _infer_builtin, + klass=nodes.Tuple, + iterables=(nodes.List, nodes.Set), + build_elts=tuple) + +infer_list = partial( + _infer_builtin, + klass=nodes.List, + iterables=(nodes.Tuple, nodes.Set), + build_elts=list) + +infer_set = partial( + _infer_builtin, + klass=nodes.Set, + iterables=(nodes.List, nodes.Tuple), + build_elts=set) + + +def _get_elts(arg, context): + is_iterable = lambda n: isinstance(n, + (nodes.List, nodes.Tuple, nodes.Set)) + try: + infered = next(arg.infer(context)) + except (InferenceError, UnresolvableName): + raise UseInferenceDefault() + if isinstance(infered, nodes.Dict): + items = infered.items + elif is_iterable(infered): + items = [] + for elt in infered.elts: + # If an item is not a pair of two items, + # then fallback to the default inference. + # Also, take in consideration only hashable items, + # tuples and consts. We are choosing Names as well. + if not is_iterable(elt): + raise UseInferenceDefault() + if len(elt.elts) != 2: + raise UseInferenceDefault() + if not isinstance(elt.elts[0], + (nodes.Tuple, nodes.Const, nodes.Name)): + raise UseInferenceDefault() + items.append(tuple(elt.elts)) + else: + raise UseInferenceDefault() + return items + +def infer_dict(node, context=None): + """Try to infer a dict call to a Dict node. + + The function treats the following cases: + + * dict() + * dict(mapping) + * dict(iterable) + * dict(iterable, **kwargs) + * dict(mapping, **kwargs) + * dict(**kwargs) + + If a case can't be infered, we'll fallback to default inference. + """ + has_keywords = lambda args: all(isinstance(arg, nodes.Keyword) + for arg in args) + if not node.args and not node.kwargs: + # dict() + return nodes.Dict() + elif has_keywords(node.args) and node.args: + # dict(a=1, b=2, c=4) + items = [(nodes.Const(arg.arg), arg.value) for arg in node.args] + elif (len(node.args) >= 2 and + has_keywords(node.args[1:])): + # dict(some_iterable, b=2, c=4) + elts = _get_elts(node.args[0], context) + keys = [(nodes.Const(arg.arg), arg.value) for arg in node.args[1:]] + items = elts + keys + elif len(node.args) == 1: + items = _get_elts(node.args[0], context) + else: + raise UseInferenceDefault() + + empty = nodes.Dict() + empty.items = items + return empty + +# Builtins inference +register_builtin_transform(infer_tuple, 'tuple') +register_builtin_transform(infer_set, 'set') +register_builtin_transform(infer_list, 'list') +register_builtin_transform(infer_dict, 'dict') diff -Nru astroid-1.0.1/astroid/brain/py2gi.py astroid-1.3.8/astroid/brain/py2gi.py --- astroid-1.0.1/astroid/brain/py2gi.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/brain/py2gi.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,155 @@ +"""Astroid hooks for the Python 2 GObject introspection bindings. + +Helps with understanding everything imported from 'gi.repository' +""" + +import inspect +import itertools +import sys +import re + +from astroid import MANAGER, AstroidBuildingException +from astroid.builder import AstroidBuilder + + +_inspected_modules = {} + +_identifier_re = r'^[A-Za-z_]\w*$' + +def _gi_build_stub(parent): + """ + Inspect the passed module recursively and build stubs for functions, + classes, etc. + """ + classes = {} + functions = {} + constants = {} + methods = {} + for name in dir(parent): + if name.startswith("__"): + continue + + # Check if this is a valid name in python + if not re.match(_identifier_re, name): + continue + + try: + obj = getattr(parent, name) + except: + continue + + if inspect.isclass(obj): + classes[name] = obj + elif (inspect.isfunction(obj) or + inspect.isbuiltin(obj)): + functions[name] = obj + elif (inspect.ismethod(obj) or + inspect.ismethoddescriptor(obj)): + methods[name] = obj + elif type(obj) in [int, str]: + constants[name] = obj + elif (str(obj).startswith(" (3, 0) +PY33 = sys.version_info >= (3, 3) + +# general function + +def infer_func_form(node, base_type, context=None, enum=False): + """Specific inference function for namedtuple or Python 3 enum. """ + def infer_first(node): + try: + value = next(node.infer(context=context)) + if value is YES: + raise UseInferenceDefault() + else: + return value + except StopIteration: + raise InferenceError() + + # node is a CallFunc node, class name as first argument and generated class + # attributes as second argument + if len(node.args) != 2: + # something weird here, go back to class implementation + raise UseInferenceDefault() + # namedtuple or enums list of attributes can be a list of strings or a + # whitespace-separate string + try: + name = infer_first(node.args[0]).value + names = infer_first(node.args[1]) + try: + attributes = names.value.replace(',', ' ').split() + except AttributeError: + if not enum: + attributes = [infer_first(const).value for const in names.elts] + else: + # Enums supports either iterator of (name, value) pairs + # or mappings. + # TODO: support only list, tuples and mappings. + if hasattr(names, 'items') and isinstance(names.items, list): + attributes = [infer_first(const[0]).value + for const in names.items + if isinstance(const[0], nodes.Const)] + elif hasattr(names, 'elts'): + # Enums can support either ["a", "b", "c"] + # or [("a", 1), ("b", 2), ...], but they can't + # be mixed. + if all(isinstance(const, nodes.Tuple) + for const in names.elts): + attributes = [infer_first(const.elts[0]).value + for const in names.elts + if isinstance(const, nodes.Tuple)] + else: + attributes = [infer_first(const).value + for const in names.elts] + else: + raise AttributeError + if not attributes: + raise AttributeError + except (AttributeError, exceptions.InferenceError) as exc: + raise UseInferenceDefault() + # we want to return a Class node instance with proper attributes set + class_node = nodes.Class(name, 'docstring') + class_node.parent = node.parent + # set base class=tuple + class_node.bases.append(base_type) + # XXX add __init__(*attributes) method + for attr in attributes: + fake_node = nodes.EmptyNode() + fake_node.parent = class_node + class_node.instance_attrs[attr] = [fake_node] + return class_node, name, attributes + + +# module specific transformation functions ##################################### + +def hashlib_transform(): + template = ''' + +class %(name)s(object): + def __init__(self, value=''): pass + def digest(self): + return %(digest)s + def copy(self): + return self + def update(self, value): pass + def hexdigest(self): + return '' + @property + def name(self): + return %(name)r + @property + def block_size(self): + return 1 + @property + def digest_size(self): + return 1 +''' + algorithms = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') + classes = "".join( + template % {'name': hashfunc, 'digest': 'b""' if PY3K else '""'} + for hashfunc in algorithms) + return AstroidBuilder(MANAGER).string_build(classes) + + +def collections_transform(): + return AstroidBuilder(MANAGER).string_build(''' + +class defaultdict(dict): + default_factory = None + def __missing__(self, key): pass + +class deque(object): + maxlen = 0 + def __init__(self, iterable=None, maxlen=None): pass + def append(self, x): pass + def appendleft(self, x): pass + def clear(self): pass + def count(self, x): return 0 + def extend(self, iterable): pass + def extendleft(self, iterable): pass + def pop(self): pass + def popleft(self): pass + def remove(self, value): pass + def reverse(self): pass + def rotate(self, n): pass + def __iter__(self): return self + +''') + + +def pkg_resources_transform(): + return AstroidBuilder(MANAGER).string_build(''' + +def resource_exists(package_or_requirement, resource_name): + pass + +def resource_isdir(package_or_requirement, resource_name): + pass + +def resource_filename(package_or_requirement, resource_name): + pass + +def resource_stream(package_or_requirement, resource_name): + pass + +def resource_string(package_or_requirement, resource_name): + pass + +def resource_listdir(package_or_requirement, resource_name): + pass + +def extraction_error(): + pass + +def get_cache_path(archive_name, names=()): + pass + +def postprocess(tempname, filename): + pass + +def set_extraction_path(path): + pass + +def cleanup_resources(force=False): + pass + +''') + + +def subprocess_transform(): + if PY3K: + communicate = (bytes('string', 'ascii'), bytes('string', 'ascii')) + init = """ + def __init__(self, args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0, restore_signals=True, + start_new_session=False, pass_fds=()): + pass + """ + else: + communicate = ('string', 'string') + init = """ + def __init__(self, args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0): + pass + """ + if PY33: + wait_signature = 'def wait(self, timeout=None)' + else: + wait_signature = 'def wait(self)' + return AstroidBuilder(MANAGER).string_build(''' + +class Popen(object): + returncode = pid = 0 + stdin = stdout = stderr = file() + + %(init)s + + def communicate(self, input=None): + return %(communicate)r + %(wait_signature)s: + return self.returncode + def poll(self): + return self.returncode + def send_signal(self, signal): + pass + def terminate(self): + pass + def kill(self): + pass + ''' % {'init': init, + 'communicate': communicate, + 'wait_signature': wait_signature}) + + +# namedtuple support ########################################################### + +def looks_like_namedtuple(node): + func = node.func + if type(func) is nodes.Getattr: + return func.attrname == 'namedtuple' + if type(func) is nodes.Name: + return func.name == 'namedtuple' + return False + +def infer_named_tuple(node, context=None): + """Specific inference function for namedtuple CallFunc node""" + class_node, name, attributes = infer_func_form(node, nodes.Tuple._proxied, + context=context) + fake = AstroidBuilder(MANAGER).string_build(''' +class %(name)s(tuple): + _fields = %(fields)r + def _asdict(self): + return self.__dict__ + @classmethod + def _make(cls, iterable, new=tuple.__new__, len=len): + return new(cls, iterable) + def _replace(_self, **kwds): + result = _self._make(map(kwds.pop, %(fields)r, _self)) + if kwds: + raise ValueError('Got unexpected field names: %%r' %% list(kwds)) + return result + ''' % {'name': name, 'fields': attributes}) + class_node.locals['_asdict'] = fake.body[0].locals['_asdict'] + class_node.locals['_make'] = fake.body[0].locals['_make'] + class_node.locals['_replace'] = fake.body[0].locals['_replace'] + class_node.locals['_fields'] = fake.body[0].locals['_fields'] + # we use UseInferenceDefault, we can't be a generator so return an iterator + return iter([class_node]) + +def infer_enum(node, context=None): + """ Specific inference function for enum CallFunc node. """ + enum_meta = nodes.Class("EnumMeta", 'docstring') + class_node = infer_func_form(node, enum_meta, + context=context, enum=True)[0] + return iter([class_node.instanciate_class()]) + +def infer_enum_class(node): + """ Specific inference for enums. """ + names = set(('Enum', 'IntEnum', 'enum.Enum', 'enum.IntEnum')) + for basename in node.basenames: + # TODO: doesn't handle subclasses yet. This implementation + # is a hack to support enums. + if basename not in names: + continue + if node.root().name == 'enum': + # Skip if the class is directly from enum module. + break + for local, values in node.locals.items(): + if any(not isinstance(value, nodes.AssName) + for value in values): + continue + + stmt = values[0].statement() + if isinstance(stmt.targets[0], nodes.Tuple): + targets = stmt.targets[0].itered() + else: + targets = stmt.targets + + new_targets = [] + for target in targets: + # Replace all the assignments with our mocked class. + classdef = dedent(''' + class %(name)s(object): + @property + def value(self): + # Not the best return. + return None + @property + def name(self): + return %(name)r + ''' % {'name': target.name}) + fake = AstroidBuilder(MANAGER).string_build(classdef)[target.name] + fake.parent = target.parent + for method in node.mymethods(): + fake.locals[method.name] = [method] + new_targets.append(fake.instanciate_class()) + node.locals[local] = new_targets + break + return node + + +MANAGER.register_transform(nodes.CallFunc, inference_tip(infer_named_tuple), + looks_like_namedtuple) +MANAGER.register_transform(nodes.CallFunc, inference_tip(infer_enum), + AsStringRegexpPredicate('Enum', 'func')) +MANAGER.register_transform(nodes.Class, infer_enum_class) +register_module_extender(MANAGER, 'hashlib', hashlib_transform) +register_module_extender(MANAGER, 'collections', collections_transform) +register_module_extender(MANAGER, 'pkg_resources', pkg_resources_transform) +register_module_extender(MANAGER, 'subprocess', subprocess_transform) diff -Nru astroid-1.0.1/astroid/brain/pynose.py astroid-1.3.8/astroid/brain/pynose.py --- astroid-1.0.1/astroid/brain/pynose.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/brain/pynose.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,79 @@ +# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . + +"""Hooks for nose library.""" + +import re +import textwrap + +import astroid +import astroid.builder + +_BUILDER = astroid.builder.AstroidBuilder(astroid.MANAGER) + + +def _pep8(name, caps=re.compile('([A-Z])')): + return caps.sub(lambda m: '_' + m.groups()[0].lower(), name) + + +def _nose_tools_functions(): + """Get an iterator of names and bound methods.""" + module = _BUILDER.string_build(textwrap.dedent(''' + import unittest + + class Test(unittest.TestCase): + pass + a = Test() + ''')) + try: + case = next(module['a'].infer()) + except astroid.InferenceError: + return + for method in case.methods(): + if method.name.startswith('assert') and '_' not in method.name: + pep8_name = _pep8(method.name) + yield pep8_name, astroid.BoundMethod(method, case) + + +def _nose_tools_transform(node): + for method_name, method in _nose_tools_functions(): + node.locals[method_name] = [method] + + +def _nose_tools_trivial_transform(): + """Custom transform for the nose.tools module.""" + stub = _BUILDER.string_build('''__all__ = []''') + all_entries = ['ok_', 'eq_'] + + for pep8_name, method in _nose_tools_functions(): + all_entries.append(pep8_name) + stub[pep8_name] = method + + # Update the __all__ variable, since nose.tools + # does this manually with .append. + all_assign = stub['__all__'].parent + all_object = astroid.List(all_entries) + all_object.parent = all_assign + all_assign.value = all_object + return stub + + +astroid.register_module_extender(astroid.MANAGER, 'nose.tools.trivial', + _nose_tools_trivial_transform) +astroid.MANAGER.register_transform(astroid.Module, _nose_tools_transform, + lambda n: n.name == 'nose.tools') diff -Nru astroid-1.0.1/astroid/brain/pysix_moves.py astroid-1.3.8/astroid/brain/pysix_moves.py --- astroid-1.0.1/astroid/brain/pysix_moves.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/brain/pysix_moves.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,261 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 2.1 of the License, or (at your option) any +# later version. +# +# astroid is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . + +"""Astroid hooks for six.moves.""" + +import sys +from textwrap import dedent + +from astroid import MANAGER, register_module_extender +from astroid.builder import AstroidBuilder +from astroid.exceptions import AstroidBuildingException + +def _indent(text, prefix, predicate=None): + """Adds 'prefix' to the beginning of selected lines in 'text'. + + If 'predicate' is provided, 'prefix' will only be added to the lines + where 'predicate(line)' is True. If 'predicate' is not provided, + it will default to adding 'prefix' to all non-empty lines that do not + consist solely of whitespace characters. + """ + if predicate is None: + predicate = lambda line: line.strip() + + def prefixed_lines(): + for line in text.splitlines(True): + yield prefix + line if predicate(line) else line + return ''.join(prefixed_lines()) + + +if sys.version_info[0] == 2: + _IMPORTS_2 = """ + import BaseHTTPServer + import CGIHTTPServer + import SimpleHTTPServer + + from StringIO import StringIO + from cStringIO import StringIO as cStringIO + from UserDict import UserDict + from UserList import UserList + from UserString import UserString + + import __builtin__ as builtins + import thread as _thread + import dummy_thread as _dummy_thread + import ConfigParser as configparser + import copy_reg as copyreg + from itertools import (imap as map, + ifilter as filter, + ifilterfalse as filterfalse, + izip_longest as zip_longest, + izip as zip) + import htmlentitydefs as html_entities + import HTMLParser as html_parser + import httplib as http_client + import cookielib as http_cookiejar + import Cookie as http_cookies + import Queue as queue + import repr as reprlib + from pipes import quote as shlex_quote + import SocketServer as socketserver + import SimpleXMLRPCServer as xmlrpc_server + import xmlrpclib as xmlrpc_client + import _winreg as winreg + import robotparser as urllib_robotparser + import Tkinter as tkinter + import tkFileDialog as tkinter_tkfiledialog + + input = raw_input + intern = intern + range = xrange + xrange = xrange + reduce = reduce + reload_module = reload + + class UrllibParse(object): + import urlparse as _urlparse + import urllib as _urllib + ParseResult = _urlparse.ParseResult + SplitResult = _urlparse.SplitResult + parse_qs = _urlparse.parse_qs + parse_qsl = _urlparse.parse_qsl + urldefrag = _urlparse.urldefrag + urljoin = _urlparse.urljoin + urlparse = _urlparse.urlparse + urlsplit = _urlparse.urlsplit + urlunparse = _urlparse.urlunparse + urlunsplit = _urlparse.urlunsplit + quote = _urllib.quote + quote_plus = _urllib.quote_plus + unquote = _urllib.unquote + unquote_plus = _urllib.unquote_plus + urlencode = _urllib.urlencode + splitquery = _urllib.splitquery + splittag = _urllib.splittag + splituser = _urllib.splituser + uses_fragment = _urlparse.uses_fragment + uses_netloc = _urlparse.uses_netloc + uses_params = _urlparse.uses_params + uses_query = _urlparse.uses_query + uses_relative = _urlparse.uses_relative + + class UrllibError(object): + import urllib2 as _urllib2 + import urllib as _urllib + URLError = _urllib2.URLError + HTTPError = _urllib2.HTTPError + ContentTooShortError = _urllib.ContentTooShortError + + class DummyModule(object): + pass + + class UrllibRequest(object): + import urlparse as _urlparse + import urllib2 as _urllib2 + import urllib as _urllib + urlopen = _urllib2.urlopen + install_opener = _urllib2.install_opener + build_opener = _urllib2.build_opener + pathname2url = _urllib.pathname2url + url2pathname = _urllib.url2pathname + getproxies = _urllib.getproxies + Request = _urllib2.Request + OpenerDirector = _urllib2.OpenerDirector + HTTPDefaultErrorHandler = _urllib2.HTTPDefaultErrorHandler + HTTPRedirectHandler = _urllib2.HTTPRedirectHandler + HTTPCookieProcessor = _urllib2.HTTPCookieProcessor + ProxyHandler = _urllib2.ProxyHandler + BaseHandler = _urllib2.BaseHandler + HTTPPasswordMgr = _urllib2.HTTPPasswordMgr + HTTPPasswordMgrWithDefaultRealm = _urllib2.HTTPPasswordMgrWithDefaultRealm + AbstractBasicAuthHandler = _urllib2.AbstractBasicAuthHandler + HTTPBasicAuthHandler = _urllib2.HTTPBasicAuthHandler + ProxyBasicAuthHandler = _urllib2.ProxyBasicAuthHandler + AbstractDigestAuthHandler = _urllib2.AbstractDigestAuthHandler + HTTPDigestAuthHandler = _urllib2.HTTPDigestAuthHandler + ProxyDigestAuthHandler = _urllib2.ProxyDigestAuthHandler + HTTPHandler = _urllib2.HTTPHandler + HTTPSHandler = _urllib2.HTTPSHandler + FileHandler = _urllib2.FileHandler + FTPHandler = _urllib2.FTPHandler + CacheFTPHandler = _urllib2.CacheFTPHandler + UnknownHandler = _urllib2.UnknownHandler + HTTPErrorProcessor = _urllib2.HTTPErrorProcessor + urlretrieve = _urllib.urlretrieve + urlcleanup = _urllib.urlcleanup + proxy_bypass = _urllib.proxy_bypass + + urllib_parse = UrllibParse() + urllib_error = UrllibError() + urllib = DummyModule() + urllib.request = UrllibRequest() + urllib.parse = UrllibParse() + urllib.error = UrllibError() + """ +else: + _IMPORTS_3 = """ + import _io + cStringIO = _io.StringIO + filter = filter + from itertools import filterfalse + input = input + from sys import intern + map = map + range = range + from imp import reload as reload_module + from functools import reduce + from shlex import quote as shlex_quote + from io import StringIO + from collections import UserDict, UserList, UserString + xrange = range + zip = zip + from itertools import zip_longest + import builtins + import configparser + import copyreg + import _dummy_thread + import http.cookiejar as http_cookiejar + import http.cookies as http_cookies + import html.entities as html_entities + import html.parser as html_parser + import http.client as http_client + import http.server + BaseHTTPServer = CGIHTTPServer = SimpleHTTPServer = http.server + import pickle as cPickle + import queue + import reprlib + import socketserver + import _thread + import winreg + import xmlrpc.server as xmlrpc_server + import xmlrpc.client as xmlrpc_client + import urllib.robotparser as urllib_robotparser + import email.mime.multipart as email_mime_multipart + import email.mime.nonmultipart as email_mime_nonmultipart + import email.mime.text as email_mime_text + import email.mime.base as email_mime_base + import urllib.parse as urllib_parse + import urllib.error as urllib_error + import tkinter + import tkinter.dialog as tkinter_dialog + import tkinter.filedialog as tkinter_filedialog + import tkinter.scrolledtext as tkinter_scrolledtext + import tkinter.simpledialog as tkinder_simpledialog + import tkinter.tix as tkinter_tix + import tkinter.ttk as tkinter_ttk + import tkinter.constants as tkinter_constants + import tkinter.dnd as tkinter_dnd + import tkinter.colorchooser as tkinter_colorchooser + import tkinter.commondialog as tkinter_commondialog + import tkinter.filedialog as tkinter_tkfiledialog + import tkinter.font as tkinter_font + import tkinter.messagebox as tkinter_messagebox + import urllib.request + import urllib.robotparser as urllib_robotparser + import urllib.parse as urllib_parse + import urllib.error as urllib_error + """ +if sys.version_info[0] == 2: + _IMPORTS = dedent(_IMPORTS_2) +else: + _IMPORTS = dedent(_IMPORTS_3) + + +def six_moves_transform(): + code = dedent(''' + class Moves(object): + {} + moves = Moves() + ''').format(_indent(_IMPORTS, " ")) + module = AstroidBuilder(MANAGER).string_build(code) + module.name = 'six.moves' + return module + + +def _six_fail_hook(modname): + if modname != 'six.moves': + raise AstroidBuildingException + module = AstroidBuilder(MANAGER).string_build(_IMPORTS) + module.name = 'six.moves' + return module + + +register_module_extender(MANAGER, 'six', six_moves_transform) +register_module_extender(MANAGER, 'requests.packages.urllib3.packages.six', + six_moves_transform) +MANAGER.register_failed_import_hook(_six_fail_hook) diff -Nru astroid-1.0.1/astroid/builder.py astroid-1.3.8/astroid/builder.py --- astroid-1.0.1/astroid/builder.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/builder.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,240 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""The AstroidBuilder makes astroid from living object and / or from _ast + +The builder is not thread safe and can't be used to parse different sources +at the same time. +""" +from __future__ import with_statement + +__docformat__ = "restructuredtext en" + +import sys +from os.path import splitext, basename, exists, abspath + +from astroid.exceptions import AstroidBuildingException, InferenceError +from astroid.raw_building import InspectBuilder +from astroid.rebuilder import TreeRebuilder +from astroid.manager import AstroidManager +from astroid.bases import YES, Instance +from astroid.modutils import modpath_from_file + +from _ast import PyCF_ONLY_AST +def parse(string): + return compile(string, "", 'exec', PyCF_ONLY_AST) + +if sys.version_info >= (3, 0): + from tokenize import detect_encoding + + def open_source_file(filename): + with open(filename, 'rb') as byte_stream: + encoding = detect_encoding(byte_stream.readline)[0] + stream = open(filename, 'r', newline=None, encoding=encoding) + try: + data = stream.read() + except UnicodeError: # wrong encodingg + # detect_encoding returns utf-8 if no encoding specified + msg = 'Wrong (%s) or no encoding specified' % encoding + raise AstroidBuildingException(msg) + return stream, encoding, data + +else: + import re + + _ENCODING_RGX = re.compile(r"\s*#+.*coding[:=]\s*([-\w.]+)") + + def _guess_encoding(string): + """get encoding from a python file as string or return None if not found + """ + # check for UTF-8 byte-order mark + if string.startswith('\xef\xbb\xbf'): + return 'UTF-8' + for line in string.split('\n', 2)[:2]: + # check for encoding declaration + match = _ENCODING_RGX.match(line) + if match is not None: + return match.group(1) + + def open_source_file(filename): + """get data for parsing a file""" + stream = open(filename, 'U') + data = stream.read() + encoding = _guess_encoding(data) + return stream, encoding, data + +# ast NG builder ############################################################## + +MANAGER = AstroidManager() + +class AstroidBuilder(InspectBuilder): + """provide astroid building methods""" + + def __init__(self, manager=None): + InspectBuilder.__init__(self) + self._manager = manager or MANAGER + + def module_build(self, module, modname=None): + """build an astroid from a living module instance + """ + node = None + path = getattr(module, '__file__', None) + if path is not None: + path_, ext = splitext(module.__file__) + if ext in ('.py', '.pyc', '.pyo') and exists(path_ + '.py'): + node = self.file_build(path_ + '.py', modname) + if node is None: + # this is a built-in module + # get a partial representation by introspection + node = self.inspect_build(module, modname=modname, path=path) + # we have to handle transformation by ourselves since the rebuilder + # isn't called for builtin nodes + # + # XXX it's then only called for Module nodes, not for underlying + # nodes + node = self._manager.transform(node) + return node + + def file_build(self, path, modname=None): + """build astroid from a source code file (i.e. from an ast) + + path is expected to be a python source file + """ + try: + stream, encoding, data = open_source_file(path) + except IOError as exc: + msg = 'Unable to load file %r (%s)' % (path, exc) + raise AstroidBuildingException(msg) + except SyntaxError as exc: # py3k encoding specification error + raise AstroidBuildingException(exc) + except LookupError as exc: # unknown encoding + raise AstroidBuildingException(exc) + with stream: + # get module name if necessary + if modname is None: + try: + modname = '.'.join(modpath_from_file(path)) + except ImportError: + modname = splitext(basename(path))[0] + # build astroid representation + module = self._data_build(data, modname, path) + return self._post_build(module, encoding) + + def string_build(self, data, modname='', path=None): + """build astroid from source code string and return rebuilded astroid""" + module = self._data_build(data, modname, path) + module.file_bytes = data.encode('utf-8') + return self._post_build(module, 'utf-8') + + def _post_build(self, module, encoding): + """handles encoding and delayed nodes + after a module has been built + """ + module.file_encoding = encoding + self._manager.cache_module(module) + # post tree building steps after we stored the module in the cache: + for from_node in module._from_nodes: + if from_node.modname == '__future__': + for symbol, _ in from_node.names: + module.future_imports.add(symbol) + self.add_from_names_to_locals(from_node) + # handle delayed assattr nodes + for delayed in module._delayed_assattr: + self.delayed_assattr(delayed) + return module + + def _data_build(self, data, modname, path): + """build tree node from data and add some informations""" + # this method could be wrapped with a pickle/cache function + try: + node = parse(data + '\n') + except TypeError as exc: + raise AstroidBuildingException(exc) + if path is not None: + node_file = abspath(path) + else: + node_file = '' + if modname.endswith('.__init__'): + modname = modname[:-9] + package = True + else: + package = path and path.find('__init__.py') > -1 or False + rebuilder = TreeRebuilder(self._manager) + module = rebuilder.visit_module(node, modname, node_file, package) + module._from_nodes = rebuilder._from_nodes + module._delayed_assattr = rebuilder._delayed_assattr + return module + + def add_from_names_to_locals(self, node): + """store imported names to the locals; + resort the locals if coming from a delayed node + """ + + _key_func = lambda node: node.fromlineno + def sort_locals(my_list): + my_list.sort(key=_key_func) + for (name, asname) in node.names: + if name == '*': + try: + imported = node.do_import_module() + except InferenceError: + continue + for name in imported.wildcard_import_names(): + node.parent.set_local(name, node) + sort_locals(node.parent.scope().locals[name]) + else: + node.parent.set_local(asname or name, node) + sort_locals(node.parent.scope().locals[asname or name]) + + def delayed_assattr(self, node): + """visit a AssAttr node -> add name to locals, handle members + definition + """ + try: + frame = node.frame() + for infered in node.expr.infer(): + if infered is YES: + continue + try: + if infered.__class__ is Instance: + infered = infered._proxied + iattrs = infered.instance_attrs + elif isinstance(infered, Instance): + # Const, Tuple, ... we may be wrong, may be not, but + # anyway we don't want to pollute builtin's namespace + continue + elif infered.is_function: + iattrs = infered.instance_attrs + else: + iattrs = infered.locals + except AttributeError: + # XXX log error + #import traceback + #traceback.print_exc() + continue + values = iattrs.setdefault(node.attrname, []) + if node in values: + continue + # get assign in __init__ first XXX useful ? + if frame.name == '__init__' and values and not \ + values[0].frame().name == '__init__': + values.insert(0, node) + else: + values.append(node) + except InferenceError: + pass + diff -Nru astroid-1.0.1/astroid/exceptions.py astroid-1.3.8/astroid/exceptions.py --- astroid-1.0.1/astroid/exceptions.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/exceptions.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,51 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""this module contains exceptions used in the astroid library + +""" + +__doctype__ = "restructuredtext en" + +class AstroidError(Exception): + """base exception class for all astroid related exceptions""" + +class AstroidBuildingException(AstroidError): + """exception class when we are unable to build an astroid representation""" + +class ResolveError(AstroidError): + """base class of astroid resolution/inference error""" + +class NotFoundError(ResolveError): + """raised when we are unable to resolve a name""" + +class InferenceError(ResolveError): + """raised when we are unable to infer a node""" + +class UseInferenceDefault(Exception): + """exception to be raised in custom inference function to indicate that it + should go back to the default behaviour + """ + +class UnresolvableName(InferenceError): + """raised when we are unable to resolve a name""" + +class NoDefault(AstroidError): + """raised by function's `default_value` method when an argument has + no default value + """ + diff -Nru astroid-1.0.1/astroid/inference.py astroid-1.3.8/astroid/inference.py --- astroid-1.0.1/astroid/inference.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/inference.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,405 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""this module contains a set of functions to handle inference on astroid trees +""" + +__doctype__ = "restructuredtext en" + +from itertools import chain + +from astroid import nodes + +from astroid.manager import AstroidManager +from astroid.exceptions import (AstroidError, InferenceError, NoDefault, + NotFoundError, UnresolvableName) +from astroid.bases import (YES, Instance, InferenceContext, + _infer_stmts, copy_context, path_wrapper, + raise_if_nothing_infered) +from astroid.protocols import ( + _arguments_infer_argname, + BIN_OP_METHOD, UNARY_OP_METHOD) + +MANAGER = AstroidManager() + + +class CallContext(object): + """when inferring a function call, this class is used to remember values + given as argument + """ + def __init__(self, args, starargs, dstarargs): + self.args = [] + self.nargs = {} + for arg in args: + if isinstance(arg, nodes.Keyword): + self.nargs[arg.arg] = arg.value + else: + self.args.append(arg) + self.starargs = starargs + self.dstarargs = dstarargs + + def infer_argument(self, funcnode, name, context): + """infer a function argument value according to the call context""" + # 1. search in named keywords + try: + return self.nargs[name].infer(context) + except KeyError: + # Function.args.args can be None in astroid (means that we don't have + # information on argnames) + argindex = funcnode.args.find_argname(name)[0] + if argindex is not None: + # 2. first argument of instance/class method + if argindex == 0 and funcnode.type in ('method', 'classmethod'): + if context.boundnode is not None: + boundnode = context.boundnode + else: + # XXX can do better ? + boundnode = funcnode.parent.frame() + if funcnode.type == 'method': + if not isinstance(boundnode, Instance): + boundnode = Instance(boundnode) + return iter((boundnode,)) + if funcnode.type == 'classmethod': + return iter((boundnode,)) + # if we have a method, extract one position + # from the index, so we'll take in account + # the extra parameter represented by `self` or `cls` + if funcnode.type in ('method', 'classmethod'): + argindex -= 1 + # 2. search arg index + try: + return self.args[argindex].infer(context) + except IndexError: + pass + # 3. search in *args (.starargs) + if self.starargs is not None: + its = [] + for infered in self.starargs.infer(context): + if infered is YES: + its.append((YES,)) + continue + try: + its.append(infered.getitem(argindex, context).infer(context)) + except (InferenceError, AttributeError): + its.append((YES,)) + except (IndexError, TypeError): + continue + if its: + return chain(*its) + # 4. XXX search in **kwargs (.dstarargs) + if self.dstarargs is not None: + its = [] + for infered in self.dstarargs.infer(context): + if infered is YES: + its.append((YES,)) + continue + try: + its.append(infered.getitem(name, context).infer(context)) + except (InferenceError, AttributeError): + its.append((YES,)) + except (IndexError, TypeError): + continue + if its: + return chain(*its) + # 5. */** argument, (Tuple or Dict) + if name == funcnode.args.vararg: + return iter((nodes.const_factory(()))) + if name == funcnode.args.kwarg: + return iter((nodes.const_factory({}))) + # 6. return default value if any + try: + return funcnode.args.default_value(name).infer(context) + except NoDefault: + raise InferenceError(name) + + +# .infer method ############################################################### + + +def infer_end(self, context=None): + """inference's end for node such as Module, Class, Function, Const... + """ + yield self +nodes.Module._infer = infer_end +nodes.Class._infer = infer_end +nodes.Function._infer = infer_end +nodes.Lambda._infer = infer_end +nodes.Const._infer = infer_end +nodes.List._infer = infer_end +nodes.Tuple._infer = infer_end +nodes.Dict._infer = infer_end +nodes.Set._infer = infer_end + +def _higher_function_scope(node): + """ Search for the first function which encloses the given + scope. This can be used for looking up in that function's + scope, in case looking up in a lower scope for a particular + name fails. + + :param node: A scope node. + :returns: + ``None``, if no parent function scope was found, + otherwise an instance of :class:`astroid.scoped_nodes.Function`, + which encloses the given node. + """ + current = node + while current.parent and not isinstance(current.parent, nodes.Function): + current = current.parent + if current and current.parent: + return current.parent + +def infer_name(self, context=None): + """infer a Name: use name lookup rules""" + frame, stmts = self.lookup(self.name) + if not stmts: + # Try to see if the name is enclosed in a nested function + # and use the higher (first function) scope for searching. + # TODO: should this be promoted to other nodes as well? + parent_function = _higher_function_scope(self.scope()) + if parent_function: + _, stmts = parent_function.lookup(self.name) + + if not stmts: + raise UnresolvableName(self.name) + context = context.clone() + context.lookupname = self.name + return _infer_stmts(stmts, context, frame) +nodes.Name._infer = path_wrapper(infer_name) +nodes.AssName.infer_lhs = infer_name # won't work with a path wrapper + + +def infer_callfunc(self, context=None): + """infer a CallFunc node by trying to guess what the function returns""" + callcontext = context.clone() + callcontext.callcontext = CallContext(self.args, self.starargs, self.kwargs) + callcontext.boundnode = None + for callee in self.func.infer(context): + if callee is YES: + yield callee + continue + try: + if hasattr(callee, 'infer_call_result'): + for infered in callee.infer_call_result(self, callcontext): + yield infered + except InferenceError: + ## XXX log error ? + continue +nodes.CallFunc._infer = path_wrapper(raise_if_nothing_infered(infer_callfunc)) + + +def infer_import(self, context=None, asname=True): + """infer an Import node: return the imported module/object""" + name = context.lookupname + if name is None: + raise InferenceError() + if asname: + yield self.do_import_module(self.real_name(name)) + else: + yield self.do_import_module(name) +nodes.Import._infer = path_wrapper(infer_import) + +def infer_name_module(self, name): + context = InferenceContext() + context.lookupname = name + return self.infer(context, asname=False) +nodes.Import.infer_name_module = infer_name_module + + +def infer_from(self, context=None, asname=True): + """infer a From nodes: return the imported module/object""" + name = context.lookupname + if name is None: + raise InferenceError() + if asname: + name = self.real_name(name) + module = self.do_import_module() + try: + context = copy_context(context) + context.lookupname = name + return _infer_stmts(module.getattr(name, ignore_locals=module is self.root()), context) + except NotFoundError: + raise InferenceError(name) +nodes.From._infer = path_wrapper(infer_from) + + +def infer_getattr(self, context=None): + """infer a Getattr node by using getattr on the associated object""" + for owner in self.expr.infer(context): + if owner is YES: + yield owner + continue + try: + context.boundnode = owner + for obj in owner.igetattr(self.attrname, context): + yield obj + context.boundnode = None + except (NotFoundError, InferenceError): + context.boundnode = None + except AttributeError: + # XXX method / function + context.boundnode = None +nodes.Getattr._infer = path_wrapper(raise_if_nothing_infered(infer_getattr)) +nodes.AssAttr.infer_lhs = raise_if_nothing_infered(infer_getattr) # # won't work with a path wrapper + + +def infer_global(self, context=None): + if context.lookupname is None: + raise InferenceError() + try: + return _infer_stmts(self.root().getattr(context.lookupname), context) + except NotFoundError: + raise InferenceError() +nodes.Global._infer = path_wrapper(infer_global) + + +def infer_subscript(self, context=None): + """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]""" + value = next(self.value.infer(context)) + if value is YES: + yield YES + return + + index = next(self.slice.infer(context)) + if index is YES: + yield YES + return + + if isinstance(index, nodes.Const): + try: + assigned = value.getitem(index.value, context) + except AttributeError: + raise InferenceError() + except (IndexError, TypeError): + yield YES + return + + # Prevent inferring if the infered subscript + # is the same as the original subscripted object. + if self is assigned: + yield YES + return + for infered in assigned.infer(context): + yield infered + else: + raise InferenceError() +nodes.Subscript._infer = path_wrapper(infer_subscript) +nodes.Subscript.infer_lhs = raise_if_nothing_infered(infer_subscript) + +def infer_unaryop(self, context=None): + for operand in self.operand.infer(context): + try: + yield operand.infer_unary_op(self.op) + except TypeError: + continue + except AttributeError: + meth = UNARY_OP_METHOD[self.op] + if meth is None: + yield YES + else: + try: + # XXX just suppose if the type implement meth, returned type + # will be the same + operand.getattr(meth) + yield operand + except GeneratorExit: + raise + except: + yield YES +nodes.UnaryOp._infer = path_wrapper(infer_unaryop) + +def _infer_binop(operator, operand1, operand2, context, failures=None): + if operand1 is YES: + yield operand1 + return + try: + for valnode in operand1.infer_binary_op(operator, operand2, context): + yield valnode + except AttributeError: + try: + # XXX just suppose if the type implement meth, returned type + # will be the same + operand1.getattr(BIN_OP_METHOD[operator]) + yield operand1 + except: + if failures is None: + yield YES + else: + failures.append(operand1) + +def infer_binop(self, context=None): + failures = [] + for lhs in self.left.infer(context): + for val in _infer_binop(self.op, lhs, self.right, context, failures): + yield val + for lhs in failures: + for rhs in self.right.infer(context): + for val in _infer_binop(self.op, rhs, lhs, context): + yield val +nodes.BinOp._infer = path_wrapper(infer_binop) + + +def infer_arguments(self, context=None): + name = context.lookupname + if name is None: + raise InferenceError() + return _arguments_infer_argname(self, name, context) +nodes.Arguments._infer = infer_arguments + + +def infer_ass(self, context=None): + """infer a AssName/AssAttr: need to inspect the RHS part of the + assign node + """ + stmt = self.statement() + if isinstance(stmt, nodes.AugAssign): + return stmt.infer(context) + stmts = list(self.assigned_stmts(context=context)) + return _infer_stmts(stmts, context) +nodes.AssName._infer = path_wrapper(infer_ass) +nodes.AssAttr._infer = path_wrapper(infer_ass) + +def infer_augassign(self, context=None): + failures = [] + for lhs in self.target.infer_lhs(context): + for val in _infer_binop(self.op, lhs, self.value, context, failures): + yield val + for lhs in failures: + for rhs in self.value.infer(context): + for val in _infer_binop(self.op, rhs, lhs, context): + yield val +nodes.AugAssign._infer = path_wrapper(infer_augassign) + + +# no infer method on DelName and DelAttr (expected InferenceError) + + +def infer_empty_node(self, context=None): + if not self.has_underlying_object(): + yield YES + else: + try: + for infered in MANAGER.infer_ast_from_something(self.object, + context=context): + yield infered + except AstroidError: + yield YES +nodes.EmptyNode._infer = path_wrapper(infer_empty_node) + + +def infer_index(self, context=None): + return self.value.infer(context) +nodes.Index._infer = infer_index diff -Nru astroid-1.0.1/astroid/__init__.py astroid-1.3.8/astroid/__init__.py --- astroid-1.0.1/astroid/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/__init__.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,131 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""Python Abstract Syntax Tree New Generation + +The aim of this module is to provide a common base representation of +python source code for projects such as pychecker, pyreverse, +pylint... Well, actually the development of this library is essentially +governed by pylint's needs. + +It extends class defined in the python's _ast module with some +additional methods and attributes. Instance attributes are added by a +builder object, which can either generate extended ast (let's call +them astroid ;) by visiting an existent ast tree or by inspecting living +object. Methods are added by monkey patching ast classes. + +Main modules are: + +* nodes and scoped_nodes for more information about methods and + attributes added to different node classes + +* the manager contains a high level object to get astroid trees from + source files and living objects. It maintains a cache of previously + constructed tree for quick access + +* builder contains the class responsible to build astroid trees +""" +__doctype__ = "restructuredtext en" + +import sys +import re +from operator import attrgetter + +# WARNING: internal imports order matters ! + +# make all exception classes accessible from astroid package +from astroid.exceptions import * + +# make all node classes accessible from astroid package +from astroid.nodes import * + +# trigger extra monkey-patching +from astroid import inference + +# more stuff available +from astroid import raw_building +from astroid.bases import YES, Instance, BoundMethod, UnboundMethod +from astroid.node_classes import are_exclusive, unpack_infer +from astroid.scoped_nodes import builtin_lookup + +# make a manager instance (borg) as well as Project and Package classes +# accessible from astroid package +from astroid.manager import AstroidManager, Project +MANAGER = AstroidManager() +del AstroidManager + +# transform utilities (filters and decorator) + +class AsStringRegexpPredicate(object): + """Class to be used as predicate that may be given to `register_transform` + + First argument is a regular expression that will be searched against the `as_string` + representation of the node onto which it's applied. + + If specified, the second argument is an `attrgetter` expression that will be + applied on the node first to get the actual node on which `as_string` should + be called. + + WARNING: This can be fairly slow, as it has to convert every AST node back + to Python code; you should consider examining the AST directly instead. + """ + def __init__(self, regexp, expression=None): + self.regexp = re.compile(regexp) + self.expression = expression + + def __call__(self, node): + if self.expression is not None: + node = attrgetter(self.expression)(node) + return self.regexp.search(node.as_string()) + +def inference_tip(infer_function): + """Given an instance specific inference function, return a function to be + given to MANAGER.register_transform to set this inference function. + + Typical usage + + .. sourcecode:: python + + MANAGER.register_transform(CallFunc, inference_tip(infer_named_tuple), + predicate) + """ + def transform(node, infer_function=infer_function): + node._explicit_inference = infer_function + return node + return transform + + +def register_module_extender(manager, module_name, get_extension_mod): + def transform(node): + extension_module = get_extension_mod() + for name, obj in extension_module.locals.items(): + node.locals[name] = obj + + manager.register_transform(Module, transform, lambda n: n.name == module_name) + + +# load brain plugins +from os import listdir +from os.path import join, dirname +BRAIN_MODULES_DIR = join(dirname(__file__), 'brain') +if BRAIN_MODULES_DIR not in sys.path: + # add it to the end of the list so user path take precedence + sys.path.append(BRAIN_MODULES_DIR) +# load modules in this directory +for module in listdir(BRAIN_MODULES_DIR): + if module.endswith('.py'): + __import__(module[:-3]) diff -Nru astroid-1.0.1/astroid/inspector.py astroid-1.3.8/astroid/inspector.py --- astroid-1.0.1/astroid/inspector.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/inspector.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,273 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""visitor doing some postprocessing on the astroid tree. +Try to resolve definitions (namespace) dictionary, relationship... + +This module has been imported from pyreverse +""" + +__docformat__ = "restructuredtext en" + +from os.path import dirname + +import astroid +from astroid.exceptions import InferenceError +from astroid.utils import LocalsVisitor +from astroid.modutils import get_module_part, is_relative, is_standard_module + +class IdGeneratorMixIn(object): + """ + Mixin adding the ability to generate integer uid + """ + def __init__(self, start_value=0): + self.id_count = start_value + + def init_counter(self, start_value=0): + """init the id counter + """ + self.id_count = start_value + + def generate_id(self): + """generate a new identifier + """ + self.id_count += 1 + return self.id_count + + +class Linker(IdGeneratorMixIn, LocalsVisitor): + """ + walk on the project tree and resolve relationships. + + According to options the following attributes may be added to visited nodes: + + * uid, + a unique identifier for the node (on astroid.Project, astroid.Module, + astroid.Class and astroid.locals_type). Only if the linker has been instantiated + with tag=True parameter (False by default). + + * Function + a mapping from locals names to their bounded value, which may be a + constant like a string or an integer, or an astroid node (on astroid.Module, + astroid.Class and astroid.Function). + + * instance_attrs_type + as locals_type but for klass member attributes (only on astroid.Class) + + * implements, + list of implemented interface _objects_ (only on astroid.Class nodes) + """ + + def __init__(self, project, inherited_interfaces=0, tag=False): + IdGeneratorMixIn.__init__(self) + LocalsVisitor.__init__(self) + # take inherited interface in consideration or not + self.inherited_interfaces = inherited_interfaces + # tag nodes or not + self.tag = tag + # visited project + self.project = project + + + def visit_project(self, node): + """visit an astroid.Project node + + * optionally tag the node with a unique id + """ + if self.tag: + node.uid = self.generate_id() + for module in node.modules: + self.visit(module) + + def visit_package(self, node): + """visit an astroid.Package node + + * optionally tag the node with a unique id + """ + if self.tag: + node.uid = self.generate_id() + for subelmt in node.values(): + self.visit(subelmt) + + def visit_module(self, node): + """visit an astroid.Module node + + * set the locals_type mapping + * set the depends mapping + * optionally tag the node with a unique id + """ + if hasattr(node, 'locals_type'): + return + node.locals_type = {} + node.depends = [] + if self.tag: + node.uid = self.generate_id() + + def visit_class(self, node): + """visit an astroid.Class node + + * set the locals_type and instance_attrs_type mappings + * set the implements list and build it + * optionally tag the node with a unique id + """ + if hasattr(node, 'locals_type'): + return + node.locals_type = {} + if self.tag: + node.uid = self.generate_id() + # resolve ancestors + for baseobj in node.ancestors(recurs=False): + specializations = getattr(baseobj, 'specializations', []) + specializations.append(node) + baseobj.specializations = specializations + # resolve instance attributes + node.instance_attrs_type = {} + for assattrs in node.instance_attrs.values(): + for assattr in assattrs: + self.handle_assattr_type(assattr, node) + # resolve implemented interface + try: + node.implements = list(node.interfaces(self.inherited_interfaces)) + except InferenceError: + node.implements = () + + def visit_function(self, node): + """visit an astroid.Function node + + * set the locals_type mapping + * optionally tag the node with a unique id + """ + if hasattr(node, 'locals_type'): + return + node.locals_type = {} + if self.tag: + node.uid = self.generate_id() + + link_project = visit_project + link_module = visit_module + link_class = visit_class + link_function = visit_function + + def visit_assname(self, node): + """visit an astroid.AssName node + + handle locals_type + """ + # avoid double parsing done by different Linkers.visit + # running over the same project: + if hasattr(node, '_handled'): + return + node._handled = True + if node.name in node.frame(): + frame = node.frame() + else: + # the name has been defined as 'global' in the frame and belongs + # there. Btw the frame is not yet visited as the name is in the + # root locals; the frame hence has no locals_type attribute + frame = node.root() + try: + values = node.infered() + try: + already_infered = frame.locals_type[node.name] + for valnode in values: + if not valnode in already_infered: + already_infered.append(valnode) + except KeyError: + frame.locals_type[node.name] = values + except astroid.InferenceError: + pass + + def handle_assattr_type(self, node, parent): + """handle an astroid.AssAttr node + + handle instance_attrs_type + """ + try: + values = list(node.infer()) + try: + already_infered = parent.instance_attrs_type[node.attrname] + for valnode in values: + if not valnode in already_infered: + already_infered.append(valnode) + except KeyError: + parent.instance_attrs_type[node.attrname] = values + except astroid.InferenceError: + pass + + def visit_import(self, node): + """visit an astroid.Import node + + resolve module dependencies + """ + context_file = node.root().file + for name in node.names: + relative = is_relative(name[0], context_file) + self._imported_module(node, name[0], relative) + + + def visit_from(self, node): + """visit an astroid.From node + + resolve module dependencies + """ + basename = node.modname + context_file = node.root().file + if context_file is not None: + relative = is_relative(basename, context_file) + else: + relative = False + for name in node.names: + if name[0] == '*': + continue + # analyze dependencies + fullname = '%s.%s' % (basename, name[0]) + if fullname.find('.') > -1: + try: + # XXX: don't use get_module_part, missing package precedence + fullname = get_module_part(fullname, context_file) + except ImportError: + continue + if fullname != basename: + self._imported_module(node, fullname, relative) + + + def compute_module(self, context_name, mod_path): + """return true if the module should be added to dependencies""" + package_dir = dirname(self.project.path) + if context_name == mod_path: + return 0 + elif is_standard_module(mod_path, (package_dir,)): + return 1 + return 0 + + # protected methods ######################################################## + + def _imported_module(self, node, mod_path, relative): + """notify an imported module, used to analyze dependencies + """ + module = node.root() + context_name = module.name + if relative: + mod_path = '%s.%s' % ('.'.join(context_name.split('.')[:-1]), + mod_path) + if self.compute_module(context_name, mod_path): + # handle dependencies + if not hasattr(module, 'depends'): + module.depends = [] + mod_paths = module.depends + if not mod_path in mod_paths: + mod_paths.append(mod_path) diff -Nru astroid-1.0.1/astroid/manager.py astroid-1.3.8/astroid/manager.py --- astroid-1.0.1/astroid/manager.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/manager.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,391 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""astroid manager: avoid multiple astroid build of a same module when +possible by providing a class responsible to get astroid representation +from various source and using a cache of built modules) +""" +from __future__ import print_function + +__docformat__ = "restructuredtext en" + +import collections +import imp +import os +from os.path import dirname, join, isdir, exists +from warnings import warn +import zipimport + +from logilab.common.configuration import OptionsProviderMixIn + +from astroid.exceptions import AstroidBuildingException +from astroid import modutils + + +def astroid_wrapper(func, modname): + """wrapper to give to AstroidManager.project_from_files""" + print('parsing %s...' % modname) + try: + return func(modname) + except AstroidBuildingException as exc: + print(exc) + except Exception as exc: + import traceback + traceback.print_exc() + +def _silent_no_wrap(func, modname): + """silent wrapper that doesn't do anything; can be used for tests""" + return func(modname) + +def safe_repr(obj): + try: + return repr(obj) + except: + return '???' + + + +class AstroidManager(OptionsProviderMixIn): + """the astroid manager, responsible to build astroid from files + or modules. + + Use the Borg pattern. + """ + + name = 'astroid loader' + options = (("ignore", + {'type' : "csv", 'metavar' : "", + 'dest' : "black_list", "default" : ('CVS',), + 'help' : "add (may be a directory) to the black list\ +. It should be a base name, not a path. You may set this option multiple times\ +."}), + ("project", + {'default': "No Name", 'type' : 'string', 'short': 'p', + 'metavar' : '', + 'help' : 'set the project name.'}), + ) + brain = {} + def __init__(self): + self.__dict__ = AstroidManager.brain + if not self.__dict__: + OptionsProviderMixIn.__init__(self) + self.load_defaults() + # NOTE: cache entries are added by the [re]builder + self.astroid_cache = {} + self._mod_file_cache = {} + self.transforms = collections.defaultdict(list) + self._failed_import_hooks = [] + self.always_load_extensions = False + self.optimize_ast = False + self.extension_package_whitelist = set() + + def ast_from_file(self, filepath, modname=None, fallback=True, source=False): + """given a module name, return the astroid object""" + try: + filepath = modutils.get_source_file(filepath, include_no_ext=True) + source = True + except modutils.NoSourceFile: + pass + if modname is None: + try: + modname = '.'.join(modutils.modpath_from_file(filepath)) + except ImportError: + modname = filepath + if modname in self.astroid_cache and self.astroid_cache[modname].file == filepath: + return self.astroid_cache[modname] + if source: + from astroid.builder import AstroidBuilder + return AstroidBuilder(self).file_build(filepath, modname) + elif fallback and modname: + return self.ast_from_module_name(modname) + raise AstroidBuildingException('unable to get astroid for file %s' % + filepath) + + def _build_stub_module(self, modname): + from astroid.builder import AstroidBuilder + return AstroidBuilder(self).string_build('', modname) + + def _can_load_extension(self, modname): + if self.always_load_extensions: + return True + if modutils.is_standard_module(modname): + return True + parts = modname.split('.') + return any( + '.'.join(parts[:x]) in self.extension_package_whitelist + for x in range(1, len(parts) + 1)) + + def ast_from_module_name(self, modname, context_file=None): + """given a module name, return the astroid object""" + if modname in self.astroid_cache: + return self.astroid_cache[modname] + if modname == '__main__': + return self._build_stub_module(modname) + old_cwd = os.getcwd() + if context_file: + os.chdir(dirname(context_file)) + try: + filepath, mp_type = self.file_from_module_name(modname, context_file) + if mp_type == modutils.PY_ZIPMODULE: + module = self.zip_import_data(filepath) + if module is not None: + return module + elif mp_type in (imp.C_BUILTIN, imp.C_EXTENSION): + if mp_type == imp.C_EXTENSION and not self._can_load_extension(modname): + return self._build_stub_module(modname) + try: + module = modutils.load_module_from_name(modname) + except Exception as ex: + msg = 'Unable to load module %s (%s)' % (modname, ex) + raise AstroidBuildingException(msg) + return self.ast_from_module(module, modname) + elif mp_type == imp.PY_COMPILED: + raise AstroidBuildingException("Unable to load compiled module %s" % (modname,)) + if filepath is None: + raise AstroidBuildingException("Unable to load module %s" % (modname,)) + return self.ast_from_file(filepath, modname, fallback=False) + except AstroidBuildingException as e: + for hook in self._failed_import_hooks: + try: + return hook(modname) + except AstroidBuildingException: + pass + raise e + finally: + os.chdir(old_cwd) + + def zip_import_data(self, filepath): + if zipimport is None: + return None + from astroid.builder import AstroidBuilder + builder = AstroidBuilder(self) + for ext in ('.zip', '.egg'): + try: + eggpath, resource = filepath.rsplit(ext + os.path.sep, 1) + except ValueError: + continue + try: + importer = zipimport.zipimporter(eggpath + ext) + zmodname = resource.replace(os.path.sep, '.') + if importer.is_package(resource): + zmodname = zmodname + '.__init__' + module = builder.string_build(importer.get_source(resource), + zmodname, filepath) + return module + except: + continue + return None + + def file_from_module_name(self, modname, contextfile): + try: + value = self._mod_file_cache[(modname, contextfile)] + except KeyError: + try: + value = modutils.file_info_from_modpath( + modname.split('.'), context_file=contextfile) + except ImportError as ex: + msg = 'Unable to load module %s (%s)' % (modname, ex) + value = AstroidBuildingException(msg) + self._mod_file_cache[(modname, contextfile)] = value + if isinstance(value, AstroidBuildingException): + raise value + return value + + def ast_from_module(self, module, modname=None): + """given an imported module, return the astroid object""" + modname = modname or module.__name__ + if modname in self.astroid_cache: + return self.astroid_cache[modname] + try: + # some builtin modules don't have __file__ attribute + filepath = module.__file__ + if modutils.is_python_source(filepath): + return self.ast_from_file(filepath, modname) + except AttributeError: + pass + from astroid.builder import AstroidBuilder + return AstroidBuilder(self).module_build(module, modname) + + def ast_from_class(self, klass, modname=None): + """get astroid for the given class""" + if modname is None: + try: + modname = klass.__module__ + except AttributeError: + raise AstroidBuildingException( + 'Unable to get module for class %s' % safe_repr(klass)) + modastroid = self.ast_from_module_name(modname) + return modastroid.getattr(klass.__name__)[0] # XXX + + + def infer_ast_from_something(self, obj, context=None): + """infer astroid for the given class""" + if hasattr(obj, '__class__') and not isinstance(obj, type): + klass = obj.__class__ + else: + klass = obj + try: + modname = klass.__module__ + except AttributeError: + raise AstroidBuildingException( + 'Unable to get module for %s' % safe_repr(klass)) + except Exception as ex: + raise AstroidBuildingException( + 'Unexpected error while retrieving module for %s: %s' + % (safe_repr(klass), ex)) + try: + name = klass.__name__ + except AttributeError: + raise AstroidBuildingException( + 'Unable to get name for %s' % safe_repr(klass)) + except Exception as ex: + raise AstroidBuildingException( + 'Unexpected error while retrieving name for %s: %s' + % (safe_repr(klass), ex)) + # take care, on living object __module__ is regularly wrong :( + modastroid = self.ast_from_module_name(modname) + if klass is obj: + for infered in modastroid.igetattr(name, context): + yield infered + else: + for infered in modastroid.igetattr(name, context): + yield infered.instanciate_class() + + def project_from_files(self, files, func_wrapper=astroid_wrapper, + project_name=None, black_list=None): + """return a Project from a list of files or modules""" + # build the project representation + project_name = project_name or self.config.project + black_list = black_list or self.config.black_list + project = Project(project_name) + for something in files: + if not exists(something): + fpath = modutils.file_from_modpath(something.split('.')) + elif isdir(something): + fpath = join(something, '__init__.py') + else: + fpath = something + astroid = func_wrapper(self.ast_from_file, fpath) + if astroid is None: + continue + # XXX why is first file defining the project.path ? + project.path = project.path or astroid.file + project.add_module(astroid) + base_name = astroid.name + # recurse in package except if __init__ was explicitly given + if astroid.package and something.find('__init__') == -1: + # recurse on others packages / modules if this is a package + for fpath in modutils.get_module_files(dirname(astroid.file), + black_list): + astroid = func_wrapper(self.ast_from_file, fpath) + if astroid is None or astroid.name == base_name: + continue + project.add_module(astroid) + return project + + def register_transform(self, node_class, transform, predicate=None): + """Register `transform(node)` function to be applied on the given + Astroid's `node_class` if `predicate` is None or returns true + when called with the node as argument. + + The transform function may return a value which is then used to + substitute the original node in the tree. + """ + self.transforms[node_class].append((transform, predicate)) + + def unregister_transform(self, node_class, transform, predicate=None): + """Unregister the given transform.""" + self.transforms[node_class].remove((transform, predicate)) + + def register_failed_import_hook(self, hook): + """Registers a hook to resolve imports that cannot be found otherwise. + + `hook` must be a function that accepts a single argument `modname` which + contains the name of the module or package that could not be imported. + If `hook` can resolve the import, must return a node of type `astroid.Module`, + otherwise, it must raise `AstroidBuildingException`. + """ + self._failed_import_hooks.append(hook) + + def transform(self, node): + """Call matching transforms for the given node if any and return the + transformed node. + """ + cls = node.__class__ + if cls not in self.transforms: + # no transform registered for this class of node + return node + + transforms = self.transforms[cls] + orig_node = node # copy the reference + for transform_func, predicate in transforms: + if predicate is None or predicate(node): + ret = transform_func(node) + # if the transformation function returns something, it's + # expected to be a replacement for the node + if ret is not None: + if node is not orig_node: + # node has already be modified by some previous + # transformation, warn about it + warn('node %s substituted multiple times' % node) + node = ret + return node + + def cache_module(self, module): + """Cache a module if no module with the same name is known yet.""" + self.astroid_cache.setdefault(module.name, module) + + def clear_cache(self, astroid_builtin=None): + # XXX clear transforms + self.astroid_cache.clear() + # force bootstrap again, else we may ends up with cache inconsistency + # between the manager and CONST_PROXY, making + # unittest_lookup.LookupTC.test_builtin_lookup fail depending on the + # test order + import astroid.raw_building + astroid.raw_building._astroid_bootstrapping( + astroid_builtin=astroid_builtin) + + +class Project(object): + """a project handle a set of modules / packages""" + def __init__(self, name=''): + self.name = name + self.path = None + self.modules = [] + self.locals = {} + self.__getitem__ = self.locals.__getitem__ + self.__iter__ = self.locals.__iter__ + self.values = self.locals.values + self.keys = self.locals.keys + self.items = self.locals.items + + def add_module(self, node): + self.locals[node.name] = node + self.modules.append(node) + + def get_module(self, name): + return self.locals[name] + + def get_children(self): + return self.modules + + def __repr__(self): + return '' % (self.name, id(self), + len(self.modules)) + + diff -Nru astroid-1.0.1/astroid/mixins.py astroid-1.3.8/astroid/mixins.py --- astroid-1.0.1/astroid/mixins.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/mixins.py 2015-08-02 19:35:55.000000000 +0000 @@ -0,0 +1,124 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""This module contains some mixins for the different nodes. +""" + +from logilab.common.decorators import cachedproperty + +from astroid.exceptions import (AstroidBuildingException, InferenceError, + NotFoundError) + + +class BlockRangeMixIn(object): + """override block range """ + + @cachedproperty + def blockstart_tolineno(self): + return self.lineno + + def _elsed_block_range(self, lineno, orelse, last=None): + """handle block line numbers range for try/finally, for, if and while + statements + """ + if lineno == self.fromlineno: + return lineno, lineno + if orelse: + if lineno >= orelse[0].fromlineno: + return lineno, orelse[-1].tolineno + return lineno, orelse[0].fromlineno - 1 + return lineno, last or self.tolineno + + +class FilterStmtsMixin(object): + """Mixin for statement filtering and assignment type""" + + def _get_filtered_stmts(self, _, node, _stmts, mystmt): + """method used in _filter_stmts to get statemtents and trigger break""" + if self.statement() is mystmt: + # original node's statement is the assignment, only keep + # current node (gen exp, list comp) + return [node], True + return _stmts, False + + def ass_type(self): + return self + + +class AssignTypeMixin(object): + + def ass_type(self): + return self + + def _get_filtered_stmts(self, lookup_node, node, _stmts, mystmt): + """method used in filter_stmts""" + if self is mystmt: + return _stmts, True + if self.statement() is mystmt: + # original node's statement is the assignment, only keep + # current node (gen exp, list comp) + return [node], True + return _stmts, False + + +class ParentAssignTypeMixin(AssignTypeMixin): + + def ass_type(self): + return self.parent.ass_type() + + +class FromImportMixIn(FilterStmtsMixin): + """MixIn for From and Import Nodes""" + + def _infer_name(self, frame, name): + return name + + def do_import_module(self, modname=None): + """return the ast for a module whose name is imported by + """ + # handle special case where we are on a package node importing a module + # using the same name as the package, which may end in an infinite loop + # on relative imports + # XXX: no more needed ? + mymodule = self.root() + level = getattr(self, 'level', None) # Import as no level + if modname is None: + modname = self.modname + # XXX we should investigate deeper if we really want to check + # importing itself: modname and mymodule.name be relative or absolute + if mymodule.relative_to_absolute_name(modname, level) == mymodule.name: + # FIXME: we used to raise InferenceError here, but why ? + return mymodule + try: + return mymodule.import_module(modname, level=level) + except AstroidBuildingException: + raise InferenceError(modname) + except SyntaxError as ex: + raise InferenceError(str(ex)) + + def real_name(self, asname): + """get name from 'as' name""" + for name, _asname in self.names: + if name == '*': + return asname + if not _asname: + name = name.split('.', 1)[0] + _asname = name + if asname == _asname: + return name + raise NotFoundError(asname) + diff -Nru astroid-1.0.1/astroid/modutils.py astroid-1.3.8/astroid/modutils.py --- astroid-1.0.1/astroid/modutils.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/modutils.py 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,670 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 2.1 of the License, or (at your option) any +# later version. +# +# astroid is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""Python modules manipulation utility functions. + +:type PY_SOURCE_EXTS: tuple(str) +:var PY_SOURCE_EXTS: list of possible python source file extension + +:type STD_LIB_DIRS: set of str +:var STD_LIB_DIRS: directories where standard modules are located + +:type BUILTIN_MODULES: dict +:var BUILTIN_MODULES: dictionary with builtin module names has key +""" +from __future__ import with_statement + +__docformat__ = "restructuredtext en" + +import imp +import os +import sys +from distutils.sysconfig import get_python_lib +from distutils.errors import DistutilsPlatformError +import zipimport + +try: + import pkg_resources +except ImportError: + pkg_resources = None + +from logilab.common import _handle_blacklist + +PY_ZIPMODULE = object() + +if sys.platform.startswith('win'): + PY_SOURCE_EXTS = ('py', 'pyw') + PY_COMPILED_EXTS = ('dll', 'pyd') +else: + PY_SOURCE_EXTS = ('py',) + PY_COMPILED_EXTS = ('so',) + +# Notes about STD_LIB_DIRS +# Consider arch-specific installation for STD_LIB_DIRS definition +# :mod:`distutils.sysconfig` contains to much hardcoded values to rely on +# +# :see: `Problems with /usr/lib64 builds `_ +# :see: `FHS `_ +try: + # The explicit sys.prefix is to work around a patch in virtualenv that + # replaces the 'real' sys.prefix (i.e. the location of the binary) + # with the prefix from which the virtualenv was created. This throws + # off the detection logic for standard library modules, thus the + # workaround. + STD_LIB_DIRS = set([ + get_python_lib(standard_lib=True, prefix=sys.prefix), + # Take care of installations where exec_prefix != prefix. + get_python_lib(standard_lib=True, prefix=sys.exec_prefix), + get_python_lib(standard_lib=True)]) + if os.name == 'nt': + STD_LIB_DIRS.add(os.path.join(sys.prefix, 'dlls')) + try: + # real_prefix is defined when running inside virtualenv. + STD_LIB_DIRS.add(os.path.join(sys.real_prefix, 'dlls')) + except AttributeError: + pass +# get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to +# non-valid path, see https://bugs.pypy.org/issue1164 +except DistutilsPlatformError: + STD_LIB_DIRS = set() + +EXT_LIB_DIR = get_python_lib() + +BUILTIN_MODULES = dict(zip(sys.builtin_module_names, + [1]*len(sys.builtin_module_names))) + + +class NoSourceFile(Exception): + """exception raised when we are not able to get a python + source file for a precompiled file + """ + +def _normalize_path(path): + return os.path.normcase(os.path.abspath(path)) + + +_NORM_PATH_CACHE = {} + +def _cache_normalize_path(path): + """abspath with caching""" + # _module_file calls abspath on every path in sys.path every time it's + # called; on a larger codebase this easily adds up to half a second just + # assembling path components. This cache alleviates that. + try: + return _NORM_PATH_CACHE[path] + except KeyError: + if not path: # don't cache result for '' + return _normalize_path(path) + result = _NORM_PATH_CACHE[path] = _normalize_path(path) + return result + +def load_module_from_name(dotted_name, path=None, use_sys=1): + """Load a Python module from its name. + + :type dotted_name: str + :param dotted_name: python name of a module or package + + :type path: list or None + :param path: + optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + :type use_sys: bool + :param use_sys: + boolean indicating whether the sys.modules dictionary should be + used or not + + + :raise ImportError: if the module or package is not found + + :rtype: module + :return: the loaded module + """ + return load_module_from_modpath(dotted_name.split('.'), path, use_sys) + + +def load_module_from_modpath(parts, path=None, use_sys=1): + """Load a python module from its splitted name. + + :type parts: list(str) or tuple(str) + :param parts: + python name of a module or package splitted on '.' + + :type path: list or None + :param path: + optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + :type use_sys: bool + :param use_sys: + boolean indicating whether the sys.modules dictionary should be used or not + + :raise ImportError: if the module or package is not found + + :rtype: module + :return: the loaded module + """ + if use_sys: + try: + return sys.modules['.'.join(parts)] + except KeyError: + pass + modpath = [] + prevmodule = None + for part in parts: + modpath.append(part) + curname = '.'.join(modpath) + module = None + if len(modpath) != len(parts): + # even with use_sys=False, should try to get outer packages from sys.modules + module = sys.modules.get(curname) + elif use_sys: + # because it may have been indirectly loaded through a parent + module = sys.modules.get(curname) + if module is None: + mp_file, mp_filename, mp_desc = imp.find_module(part, path) + module = imp.load_module(curname, mp_file, mp_filename, mp_desc) + # mp_file still needs to be closed. + if mp_file: + mp_file.close() + if prevmodule: + setattr(prevmodule, part, module) + _file = getattr(module, '__file__', '') + if not _file and len(modpath) != len(parts): + raise ImportError('no module in %s' % '.'.join(parts[len(modpath):])) + path = [os.path.dirname(_file)] + prevmodule = module + return module + + +def load_module_from_file(filepath, path=None, use_sys=1, extrapath=None): + """Load a Python module from it's path. + + :type filepath: str + :param filepath: path to the python module or package + + :type path: list or None + :param path: + optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + :type use_sys: bool + :param use_sys: + boolean indicating whether the sys.modules dictionary should be + used or not + + + :raise ImportError: if the module or package is not found + + :rtype: module + :return: the loaded module + """ + modpath = modpath_from_file(filepath, extrapath) + return load_module_from_modpath(modpath, path, use_sys) + + +def _check_init(path, mod_path): + """check there are some __init__.py all along the way""" + for part in mod_path: + path = os.path.join(path, part) + if not _has_init(path): + return False + return True + + +def modpath_from_file(filename, extrapath=None): + """given a file path return the corresponding splitted module's name + (i.e name of a module or package splitted on '.') + + :type filename: str + :param filename: file's path for which we want the module's name + + :type extrapath: dict + :param extrapath: + optional extra search path, with path as key and package name for the path + as value. This is usually useful to handle package splitted in multiple + directories using __path__ trick. + + + :raise ImportError: + if the corresponding module's name has not been found + + :rtype: list(str) + :return: the corresponding splitted module's name + """ + base = os.path.splitext(os.path.abspath(filename))[0] + if extrapath is not None: + for path_ in extrapath: + path = os.path.abspath(path_) + if path and os.path.normcase(base[:len(path)]) == os.path.normcase(path): + submodpath = [pkg for pkg in base[len(path):].split(os.sep) + if pkg] + if _check_init(path, submodpath[:-1]): + return extrapath[path_].split('.') + submodpath + for path in sys.path: + path = _cache_normalize_path(path) + if path and os.path.normcase(base).startswith(path): + modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg] + if _check_init(path, modpath[:-1]): + return modpath + raise ImportError('Unable to find module for %s in %s' % ( + filename, ', \n'.join(sys.path))) + + +def file_from_modpath(modpath, path=None, context_file=None): + return file_info_from_modpath(modpath, path, context_file)[0] + +def file_info_from_modpath(modpath, path=None, context_file=None): + """given a mod path (i.e. splitted module / package name), return the + corresponding file, giving priority to source file over precompiled + file if it exists + + :type modpath: list or tuple + :param modpath: + splitted module's name (i.e name of a module or package splitted + on '.') + (this means explicit relative imports that start with dots have + empty strings in this list!) + + :type path: list or None + :param path: + optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + :type context_file: str or None + :param context_file: + context file to consider, necessary if the identifier has been + introduced using a relative import unresolvable in the actual + context (i.e. modutils) + + :raise ImportError: if there is no such module in the directory + + :rtype: (str or None, import type) + :return: + the path to the module's file or None if it's an integrated + builtin module such as 'sys' + """ + if context_file is not None: + context = os.path.dirname(context_file) + else: + context = context_file + if modpath[0] == 'xml': + # handle _xmlplus + try: + return _file_from_modpath(['_xmlplus'] + modpath[1:], path, context) + except ImportError: + return _file_from_modpath(modpath, path, context) + elif modpath == ['os', 'path']: + # FIXME: currently ignoring search_path... + return os.path.__file__, imp.PY_SOURCE + return _file_from_modpath(modpath, path, context) + + +def get_module_part(dotted_name, context_file=None): + """given a dotted name return the module part of the name : + + >>> get_module_part('logilab.common.modutils.get_module_part') + 'logilab.common.modutils' + + :type dotted_name: str + :param dotted_name: full name of the identifier we are interested in + + :type context_file: str or None + :param context_file: + context file to consider, necessary if the identifier has been + introduced using a relative import unresolvable in the actual + context (i.e. modutils) + + + :raise ImportError: if there is no such module in the directory + + :rtype: str or None + :return: + the module part of the name or None if we have not been able at + all to import the given name + + XXX: deprecated, since it doesn't handle package precedence over module + (see #10066) + """ + # os.path trick + if dotted_name.startswith('os.path'): + return 'os.path' + parts = dotted_name.split('.') + if context_file is not None: + # first check for builtin module which won't be considered latter + # in that case (path != None) + if parts[0] in BUILTIN_MODULES: + if len(parts) > 2: + raise ImportError(dotted_name) + return parts[0] + # don't use += or insert, we want a new list to be created ! + path = None + starti = 0 + if parts[0] == '': + assert context_file is not None, \ + 'explicit relative import, but no context_file?' + path = [] # prevent resolving the import non-relatively + starti = 1 + while parts[starti] == '': # for all further dots: change context + starti += 1 + context_file = os.path.dirname(context_file) + for i in range(starti, len(parts)): + try: + file_from_modpath(parts[starti:i+1], path=path, + context_file=context_file) + except ImportError: + if not i >= max(1, len(parts) - 2): + raise + return '.'.join(parts[:i]) + return dotted_name + + +def get_module_files(src_directory, blacklist): + """given a package directory return a list of all available python + module's files in the package and its subpackages + + :type src_directory: str + :param src_directory: + path of the directory corresponding to the package + + :type blacklist: list or tuple + :param blacklist: + optional list of files or directory to ignore, default to the value of + `logilab.common.STD_BLACKLIST` + + :rtype: list + :return: + the list of all available python module's files in the package and + its subpackages + """ + files = [] + for directory, dirnames, filenames in os.walk(src_directory): + _handle_blacklist(blacklist, dirnames, filenames) + # check for __init__.py + if not '__init__.py' in filenames: + dirnames[:] = () + continue + for filename in filenames: + if _is_python_file(filename): + src = os.path.join(directory, filename) + files.append(src) + return files + + +def get_source_file(filename, include_no_ext=False): + """given a python module's file name return the matching source file + name (the filename will be returned identically if it's a already an + absolute path to a python source file...) + + :type filename: str + :param filename: python module's file name + + + :raise NoSourceFile: if no source file exists on the file system + + :rtype: str + :return: the absolute path of the source file if it exists + """ + base, orig_ext = os.path.splitext(os.path.abspath(filename)) + for ext in PY_SOURCE_EXTS: + source_path = '%s.%s' % (base, ext) + if os.path.exists(source_path): + return source_path + if include_no_ext and not orig_ext and os.path.exists(base): + return base + raise NoSourceFile(filename) + + +def is_python_source(filename): + """ + rtype: bool + return: True if the filename is a python source file + """ + return os.path.splitext(filename)[1][1:] in PY_SOURCE_EXTS + + +def is_standard_module(modname, std_path=None): + """try to guess if a module is a standard python module (by default, + see `std_path` parameter's description) + + :type modname: str + :param modname: name of the module we are interested in + + :type std_path: list(str) or tuple(str) + :param std_path: list of path considered has standard + + + :rtype: bool + :return: + true if the module: + - is located on the path listed in one of the directory in `std_path` + - is a built-in module + """ + modname = modname.split('.')[0] + try: + filename = file_from_modpath([modname]) + except ImportError: + # import failed, i'm probably not so wrong by supposing it's + # not standard... + return False + # modules which are not living in a file are considered standard + # (sys and __builtin__ for instance) + if filename is None: + return True + filename = _normalize_path(filename) + if filename.startswith(_cache_normalize_path(EXT_LIB_DIR)): + return False + if std_path is None: + std_path = STD_LIB_DIRS + for path in std_path: + if filename.startswith(_cache_normalize_path(path)): + return True + return False + + + +def is_relative(modname, from_file): + """return true if the given module name is relative to the given + file name + + :type modname: str + :param modname: name of the module we are interested in + + :type from_file: str + :param from_file: + path of the module from which modname has been imported + + :rtype: bool + :return: + true if the module has been imported relatively to `from_file` + """ + if not os.path.isdir(from_file): + from_file = os.path.dirname(from_file) + if from_file in sys.path: + return False + try: + stream, _, _ = imp.find_module(modname.split('.')[0], [from_file]) + + # Close the stream to avoid ResourceWarnings. + if stream: + stream.close() + return True + except ImportError: + return False + + +# internal only functions ##################################################### + +def _file_from_modpath(modpath, path=None, context=None): + """given a mod path (i.e. splitted module / package name), return the + corresponding file + + this function is used internally, see `file_from_modpath`'s + documentation for more information + """ + assert len(modpath) > 0 + if context is not None: + try: + mtype, mp_filename = _module_file(modpath, [context]) + except ImportError: + mtype, mp_filename = _module_file(modpath, path) + else: + mtype, mp_filename = _module_file(modpath, path) + if mtype == imp.PY_COMPILED: + try: + return get_source_file(mp_filename), imp.PY_SOURCE + except NoSourceFile: + return mp_filename, imp.PY_COMPILED + elif mtype == imp.C_BUILTIN: + # integrated builtin module + return None, imp.C_BUILTIN + elif mtype == imp.PKG_DIRECTORY: + mp_filename = _has_init(mp_filename) + mtype = imp.PY_SOURCE + return mp_filename, mtype + +def _search_zip(modpath, pic): + for filepath, importer in pic.items(): + if importer is not None: + if importer.find_module(modpath[0]): + if not importer.find_module(os.path.sep.join(modpath)): + raise ImportError('No module named %s in %s/%s' % ( + '.'.join(modpath[1:]), filepath, modpath)) + return PY_ZIPMODULE, os.path.abspath(filepath) + os.path.sep + os.path.sep.join(modpath), filepath + raise ImportError('No module named %s' % '.'.join(modpath)) + + +def _module_file(modpath, path=None): + """get a module type / file path + + :type modpath: list or tuple + :param modpath: + splitted module's name (i.e name of a module or package splitted + on '.'), with leading empty strings for explicit relative import + + :type path: list or None + :param path: + optional list of path where the module or package should be + searched (use sys.path if nothing or None is given) + + + :rtype: tuple(int, str) + :return: the module type flag and the file path for a module + """ + # egg support compat + try: + pic = sys.path_importer_cache + _path = (path is None and sys.path or path) + for __path in _path: + if not __path in pic: + try: + pic[__path] = zipimport.zipimporter(__path) + except zipimport.ZipImportError: + pic[__path] = None + checkeggs = True + except AttributeError: + checkeggs = False + # pkg_resources support (aka setuptools namespace packages) + if (pkg_resources is not None + and modpath[0] in pkg_resources._namespace_packages + and modpath[0] in sys.modules + and len(modpath) > 1): + # setuptools has added into sys.modules a module object with proper + # __path__, get back information from there + module = sys.modules[modpath.pop(0)] + path = module.__path__ + imported = [] + while modpath: + modname = modpath[0] + # take care to changes in find_module implementation wrt builtin modules + # + # Python 2.6.6 (r266:84292, Sep 11 2012, 08:34:23) + # >>> imp.find_module('posix') + # (None, 'posix', ('', '', 6)) + # + # Python 3.3.1 (default, Apr 26 2013, 12:08:46) + # >>> imp.find_module('posix') + # (None, None, ('', '', 6)) + try: + stream, mp_filename, mp_desc = imp.find_module(modname, path) + except ImportError: + if checkeggs: + return _search_zip(modpath, pic)[:2] + raise + else: + # Don't forget to close the stream to avoid + # spurious ResourceWarnings. + if stream: + stream.close() + + if checkeggs and mp_filename: + fullabspath = [_cache_normalize_path(x) for x in _path] + try: + pathindex = fullabspath.index(os.path.dirname(_normalize_path(mp_filename))) + emtype, emp_filename, zippath = _search_zip(modpath, pic) + if pathindex > _path.index(zippath): + # an egg takes priority + return emtype, emp_filename + except ValueError: + # XXX not in _path + pass + except ImportError: + pass + checkeggs = False + imported.append(modpath.pop(0)) + mtype = mp_desc[2] + if modpath: + if mtype != imp.PKG_DIRECTORY: + raise ImportError('No module %s in %s' % ('.'.join(modpath), + '.'.join(imported))) + # XXX guess if package is using pkgutil.extend_path by looking for + # those keywords in the first four Kbytes + try: + with open(os.path.join(mp_filename, '__init__.py'), 'rb') as stream: + data = stream.read(4096) + except IOError: + path = [mp_filename] + else: + if b'pkgutil' in data and b'extend_path' in data: + # extend_path is called, search sys.path for module/packages + # of this name see pkgutil.extend_path documentation + path = [os.path.join(p, *imported) for p in sys.path + if os.path.isdir(os.path.join(p, *imported))] + else: + path = [mp_filename] + return mtype, mp_filename + +def _is_python_file(filename): + """return true if the given filename should be considered as a python file + + .pyc and .pyo are ignored + """ + for ext in ('.py', '.so', '.pyd', '.pyw'): + if filename.endswith(ext): + return True + return False + + +def _has_init(directory): + """if the given directory has a valid __init__ file, return its path, + else return None + """ + mod_or_pack = os.path.join(directory, '__init__') + for ext in PY_SOURCE_EXTS + ('pyc', 'pyo'): + if os.path.exists(mod_or_pack + '.' + ext): + return mod_or_pack + '.' + ext + return None diff -Nru astroid-1.0.1/astroid/node_classes.py astroid-1.3.8/astroid/node_classes.py --- astroid-1.0.1/astroid/node_classes.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/node_classes.py 2015-08-02 19:35:55.000000000 +0000 @@ -0,0 +1,966 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""Module for some node classes. More nodes in scoped_nodes.py +""" + +import sys + +import six +from logilab.common.decorators import cachedproperty + +from astroid.exceptions import NoDefault +from astroid.bases import (NodeNG, Statement, Instance, InferenceContext, + _infer_stmts, YES, BUILTINS) +from astroid.mixins import (BlockRangeMixIn, AssignTypeMixin, + ParentAssignTypeMixin, FromImportMixIn) + +PY3K = sys.version_info >= (3, 0) + + +def unpack_infer(stmt, context=None): + """recursively generate nodes inferred by the given statement. + If the inferred value is a list or a tuple, recurse on the elements + """ + if isinstance(stmt, (List, Tuple)): + for elt in stmt.elts: + for infered_elt in unpack_infer(elt, context): + yield infered_elt + return + # if infered is a final node, return it and stop + infered = next(stmt.infer(context)) + if infered is stmt: + yield infered + return + # else, infer recursivly, except YES object that should be returned as is + for infered in stmt.infer(context): + if infered is YES: + yield infered + else: + for inf_inf in unpack_infer(infered, context): + yield inf_inf + + +def are_exclusive(stmt1, stmt2, exceptions=None): + """return true if the two given statements are mutually exclusive + + `exceptions` may be a list of exception names. If specified, discard If + branches and check one of the statement is in an exception handler catching + one of the given exceptions. + + algorithm : + 1) index stmt1's parents + 2) climb among stmt2's parents until we find a common parent + 3) if the common parent is a If or TryExcept statement, look if nodes are + in exclusive branches + """ + # index stmt1's parents + stmt1_parents = {} + children = {} + node = stmt1.parent + previous = stmt1 + while node: + stmt1_parents[node] = 1 + children[node] = previous + previous = node + node = node.parent + # climb among stmt2's parents until we find a common parent + node = stmt2.parent + previous = stmt2 + while node: + if node in stmt1_parents: + # if the common parent is a If or TryExcept statement, look if + # nodes are in exclusive branches + if isinstance(node, If) and exceptions is None: + if (node.locate_child(previous)[1] + is not node.locate_child(children[node])[1]): + return True + elif isinstance(node, TryExcept): + c2attr, c2node = node.locate_child(previous) + c1attr, c1node = node.locate_child(children[node]) + if c1node is not c2node: + if ((c2attr == 'body' and c1attr == 'handlers' and children[node].catch(exceptions)) or + (c2attr == 'handlers' and c1attr == 'body' and previous.catch(exceptions)) or + (c2attr == 'handlers' and c1attr == 'orelse') or + (c2attr == 'orelse' and c1attr == 'handlers')): + return True + elif c2attr == 'handlers' and c1attr == 'handlers': + return previous is not children[node] + return False + previous = node + node = node.parent + return False + + +class LookupMixIn(object): + """Mixin looking up a name in the right scope + """ + + def lookup(self, name): + """lookup a variable name + + return the scope node and the list of assignments associated to the + given name according to the scope where it has been found (locals, + globals or builtin) + + The lookup is starting from self's scope. If self is not a frame itself + and the name is found in the inner frame locals, statements will be + filtered to remove ignorable statements according to self's location + """ + return self.scope().scope_lookup(self, name) + + def ilookup(self, name): + """infered lookup + + return an iterator on infered values of the statements returned by + the lookup method + """ + frame, stmts = self.lookup(name) + context = InferenceContext() + return _infer_stmts(stmts, context, frame) + + def _filter_stmts(self, stmts, frame, offset): + """filter statements to remove ignorable statements. + + If self is not a frame itself and the name is found in the inner + frame locals, statements will be filtered to remove ignorable + statements according to self's location + """ + # if offset == -1, my actual frame is not the inner frame but its parent + # + # class A(B): pass + # + # we need this to resolve B correctly + if offset == -1: + myframe = self.frame().parent.frame() + else: + myframe = self.frame() + # If the frame of this node is the same as the statement + # of this node, then the node is part of a class or + # a function definition and the frame of this node should be the + # the upper frame, not the frame of the definition. + # For more information why this is important, + # see Pylint issue #295. + # For example, for 'b', the statement is the same + # as the frame / scope: + # + # def test(b=1): + # ... + + if self.statement() is myframe and myframe.parent: + myframe = myframe.parent.frame() + if not myframe is frame or self is frame: + return stmts + mystmt = self.statement() + # line filtering if we are in the same frame + # + # 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 + mylineno = 0 + _stmts = [] + _stmt_parents = [] + 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: + break + assert hasattr(node, 'ass_type'), (node, node.scope(), + node.scope().locals) + ass_type = node.ass_type() + + if node.has_base(self): + break + + _stmts, done = ass_type._get_filtered_stmts(self, node, _stmts, mystmt) + if done: + break + + optional_assign = ass_type.optional_assign + if optional_assign and ass_type.parent_of(self): + # we are inside a loop, loop var assigment is hidding previous + # assigment + _stmts = [node] + _stmt_parents = [stmt.parent] + continue + + # XXX comment various branches below!!! + try: + pindex = _stmt_parents.index(stmt.parent) + except ValueError: + pass + else: + # we got a parent index, this means the currently visited node + # is at the same block level as a previously visited node + if _stmts[pindex].ass_type().parent_of(ass_type): + # both statements are not at the same block level + continue + # if currently visited node is following previously considered + # assignement and both are not exclusive, we can drop the + # previous one. For instance in the following code :: + # + # if a: + # x = 1 + # else: + # x = 2 + # print x + # + # we can't remove neither x = 1 nor x = 2 when looking for 'x' + # of 'print x'; while in the following :: + # + # x = 1 + # x = 2 + # print x + # + # we can remove x = 1 when we see x = 2 + # + # moreover, on loop assignment types, assignment won't + # necessarily be done if the loop has no iteration, so we don't + # want to clear previous assigments if any (hence the test on + # optional_assign) + if not (optional_assign or are_exclusive(_stmts[pindex], node)): + del _stmt_parents[pindex] + del _stmts[pindex] + if isinstance(node, AssName): + if not optional_assign and stmt.parent is mystmt.parent: + _stmts = [] + _stmt_parents = [] + elif isinstance(node, DelName): + _stmts = [] + _stmt_parents = [] + continue + if not are_exclusive(self, node): + _stmts.append(node) + _stmt_parents.append(stmt.parent) + return _stmts + +# Name classes + +class AssName(LookupMixIn, ParentAssignTypeMixin, NodeNG): + """class representing an AssName node""" + + +class DelName(LookupMixIn, ParentAssignTypeMixin, NodeNG): + """class representing a DelName node""" + + +class Name(LookupMixIn, NodeNG): + """class representing a Name node""" + + + + +##################### node classes ######################################## + +class Arguments(NodeNG, AssignTypeMixin): + """class representing an Arguments node""" + if PY3K: + # 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', + 'varargannotation', 'kwargannotation') + annotations = None + varargannotation = None + kwargannotation = None + else: + _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 + self.kwarg = kwarg + + def _infer_name(self, frame, name): + if self.parent is frame: + return name + return None + + @cachedproperty + def fromlineno(self): + lineno = super(Arguments, self).fromlineno + return max(lineno, self.parent.fromlineno or 0) + + def format_args(self): + """return arguments formatted as string""" + result = [] + if self.args: + result.append(_format_args(self.args, self.defaults)) + if self.vararg: + 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): + """return the default value for an argument + + :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] + raise NoDefault() + + def is_argument(self, name): + """return True if the name is defined in arguments""" + if name == self.vararg: + return True + if name == self.kwarg: + 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) + 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): + if isinstance(arg, Tuple): + if rec: + found = _find_arg(argname, arg.elts) + if found[0] is not None: + return found + elif arg.name == argname: + return i, arg + return None, None + + +def _format_args(args, defaults=None): + values = [] + if args is None: + return '' + if defaults is not None: + default_offset = len(args) - len(defaults) + for i, arg in enumerate(args): + if isinstance(arg, Tuple): + values.append('(%s)' % _format_args(arg.elts)) + else: + values.append(arg.name) + 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) + + +class AssAttr(NodeNG, ParentAssignTypeMixin): + """class representing an AssAttr node""" + _astroid_fields = ('expr',) + expr = None + +class Assert(Statement): + """class representing an Assert node""" + _astroid_fields = ('test', 'fail',) + test = None + fail = None + +class Assign(Statement, AssignTypeMixin): + """class representing an Assign node""" + _astroid_fields = ('targets', 'value',) + targets = None + value = None + +class AugAssign(Statement, AssignTypeMixin): + """class representing an AugAssign node""" + _astroid_fields = ('target', 'value',) + target = None + value = None + +class Backquote(NodeNG): + """class representing a Backquote node""" + _astroid_fields = ('value',) + value = None + +class BinOp(NodeNG): + """class representing a BinOp node""" + _astroid_fields = ('left', 'right',) + left = None + right = None + +class BoolOp(NodeNG): + """class representing a BoolOp node""" + _astroid_fields = ('values',) + values = None + +class Break(Statement): + """class representing a Break node""" + + +class CallFunc(NodeNG): + """class representing a CallFunc node""" + _astroid_fields = ('func', 'args', 'starargs', 'kwargs') + func = None + args = None + starargs = None + kwargs = None + + def __init__(self): + self.starargs = None + self.kwargs = None + +class Compare(NodeNG): + """class representing a Compare node""" + _astroid_fields = ('left', 'ops',) + left = None + ops = None + + def get_children(self): + """override get_children for tuple fields""" + yield self.left + for _, comparator in self.ops: + yield comparator # we don't want the 'op' + + def last_child(self): + """override last_child""" + # XXX maybe if self.ops: + return self.ops[-1][1] + #return self.left + +class Comprehension(NodeNG): + """class representing a Comprehension node""" + _astroid_fields = ('target', 'iter', 'ifs') + target = None + iter = None + ifs = None + + optional_assign = True + def ass_type(self): + return self + + def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt): + """method used in filter_stmts""" + if self is mystmt: + if isinstance(lookup_node, (Const, Name)): + return [lookup_node], True + + elif self.statement() is mystmt: + # original node's statement is the assignment, only keeps + # current node (gen exp, list comp) + + return [node], True + + return stmts, False + + +class Const(NodeNG, Instance): + """represent a constant node like num, str, bool, None, bytes""" + + def __init__(self, value=None): + self.value = value + + def getitem(self, index, context=None): + if isinstance(self.value, six.string_types): + return Const(self.value[index]) + raise TypeError('%r (value=%s)' % (self, self.value)) + + def has_dynamic_getattr(self): + return False + + def itered(self): + if isinstance(self.value, six.string_types): + return self.value + raise TypeError() + + def pytype(self): + return self._proxied.qname() + + +class Continue(Statement): + """class representing a Continue node""" + + +class Decorators(NodeNG): + """class representing a Decorators node""" + _astroid_fields = ('nodes',) + nodes = None + + def __init__(self, nodes=None): + self.nodes = nodes + + def scope(self): + # skip the function node to go directly to the upper level scope + return self.parent.parent.scope() + +class DelAttr(NodeNG, ParentAssignTypeMixin): + """class representing a DelAttr node""" + _astroid_fields = ('expr',) + expr = None + + +class Delete(Statement, AssignTypeMixin): + """class representing a Delete node""" + _astroid_fields = ('targets',) + targets = None + + +class Dict(NodeNG, Instance): + """class representing a Dict node""" + _astroid_fields = ('items',) + + def __init__(self, items=None): + if items is None: + self.items = [] + else: + self.items = [(const_factory(k), const_factory(v)) + for k, v in items.items()] + + def pytype(self): + return '%s.dict' % BUILTINS + + def get_children(self): + """get children of a Dict node""" + # overrides get_children + for key, value in self.items: + yield key + yield value + + def last_child(self): + """override last_child""" + if self.items: + return self.items[-1][1] + return None + + def itered(self): + return self.items[::2] + + def getitem(self, lookup_key, context=None): + for key, value in self.items: + for inferedkey in key.infer(context): + if inferedkey is YES: + continue + if isinstance(inferedkey, Const) \ + and inferedkey.value == lookup_key: + return value + # This should raise KeyError, but all call sites only catch + # IndexError. Let's leave it like that for now. + raise IndexError(lookup_key) + + +class Discard(Statement): + """class representing a Discard node""" + _astroid_fields = ('value',) + value = None + + +class Ellipsis(NodeNG): + """class representing an Ellipsis node""" + + +class EmptyNode(NodeNG): + """class representing an EmptyNode node""" + + +class ExceptHandler(Statement, AssignTypeMixin): + """class representing an ExceptHandler node""" + _astroid_fields = ('type', 'name', 'body',) + type = None + name = None + body = None + + @cachedproperty + def blockstart_tolineno(self): + if self.name: + return self.name.tolineno + elif self.type: + return self.type.tolineno + else: + return self.lineno + + def catch(self, exceptions): + if self.type is None or exceptions is None: + return True + for node in self.type.nodes_of_class(Name): + if node.name in exceptions: + return True + + +class Exec(Statement): + """class representing an Exec node""" + _astroid_fields = ('expr', 'globals', 'locals',) + expr = None + globals = None + locals = None + + +class ExtSlice(NodeNG): + """class representing an ExtSlice node""" + _astroid_fields = ('dims',) + dims = None + +class For(BlockRangeMixIn, AssignTypeMixin, Statement): + """class representing a For node""" + _astroid_fields = ('target', 'iter', 'body', 'orelse',) + target = None + iter = None + body = None + orelse = None + + optional_assign = True + @cachedproperty + def blockstart_tolineno(self): + return self.iter.tolineno + + +class From(FromImportMixIn, Statement): + """class representing a From node""" + + def __init__(self, fromname, names, level=0): + self.modname = fromname + self.names = names + self.level = level + +class Getattr(NodeNG): + """class representing a Getattr node""" + _astroid_fields = ('expr',) + expr = None + + +class Global(Statement): + """class representing a Global node""" + + def __init__(self, names): + self.names = names + + def _infer_name(self, frame, name): + return name + + +class If(BlockRangeMixIn, Statement): + """class representing an If node""" + _astroid_fields = ('test', 'body', 'orelse') + test = None + body = None + orelse = None + + @cachedproperty + def blockstart_tolineno(self): + return self.test.tolineno + + def block_range(self, lineno): + """handle block line numbers range for if statements""" + if lineno == self.body[0].fromlineno: + return lineno, lineno + if lineno <= self.body[-1].tolineno: + return lineno, self.body[-1].tolineno + return self._elsed_block_range(lineno, self.orelse, + self.body[0].fromlineno - 1) + + +class IfExp(NodeNG): + """class representing an IfExp node""" + _astroid_fields = ('test', 'body', 'orelse') + test = None + body = None + orelse = None + + +class Import(FromImportMixIn, Statement): + """class representing an Import node""" + + +class Index(NodeNG): + """class representing an Index node""" + _astroid_fields = ('value',) + value = None + + +class Keyword(NodeNG): + """class representing a Keyword node""" + _astroid_fields = ('value',) + value = None + + +class List(NodeNG, Instance, ParentAssignTypeMixin): + """class representing a List node""" + _astroid_fields = ('elts',) + + def __init__(self, elts=None): + if elts is None: + self.elts = [] + else: + self.elts = [const_factory(e) for e in elts] + + def pytype(self): + return '%s.list' % BUILTINS + + def getitem(self, index, context=None): + return self.elts[index] + + def itered(self): + return self.elts + + +class Nonlocal(Statement): + """class representing a Nonlocal node""" + + def __init__(self, names): + self.names = names + + def _infer_name(self, frame, name): + return name + + +class Pass(Statement): + """class representing a Pass node""" + + +class Print(Statement): + """class representing a Print node""" + _astroid_fields = ('dest', 'values',) + dest = None + values = None + + +class Raise(Statement): + """class representing a Raise node""" + exc = None + if sys.version_info < (3, 0): + _astroid_fields = ('exc', 'inst', 'tback') + inst = None + tback = None + else: + _astroid_fields = ('exc', 'cause') + exc = None + cause = None + + def raises_not_implemented(self): + if not self.exc: + return + for name in self.exc.nodes_of_class(Name): + if name.name == 'NotImplementedError': + return True + + +class Return(Statement): + """class representing a Return node""" + _astroid_fields = ('value',) + value = None + + +class Set(NodeNG, Instance, ParentAssignTypeMixin): + """class representing a Set node""" + _astroid_fields = ('elts',) + + def __init__(self, elts=None): + if elts is None: + self.elts = [] + else: + self.elts = [const_factory(e) for e in elts] + + def pytype(self): + return '%s.set' % BUILTINS + + def itered(self): + return self.elts + + +class Slice(NodeNG): + """class representing a Slice node""" + _astroid_fields = ('lower', 'upper', 'step') + lower = None + upper = None + step = None + +class Starred(NodeNG, ParentAssignTypeMixin): + """class representing a Starred node""" + _astroid_fields = ('value',) + value = None + + +class Subscript(NodeNG): + """class representing a Subscript node""" + _astroid_fields = ('value', 'slice') + value = None + slice = None + + +class TryExcept(BlockRangeMixIn, Statement): + """class representing a TryExcept node""" + _astroid_fields = ('body', 'handlers', 'orelse',) + body = None + handlers = None + orelse = None + + def _infer_name(self, frame, name): + return name + + def block_range(self, lineno): + """handle block line numbers range for try/except statements""" + last = None + for exhandler in self.handlers: + if exhandler.type and lineno == exhandler.type.fromlineno: + return lineno, lineno + if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: + return lineno, exhandler.body[-1].tolineno + if last is None: + last = exhandler.body[0].fromlineno - 1 + return self._elsed_block_range(lineno, self.orelse, last) + + +class TryFinally(BlockRangeMixIn, Statement): + """class representing a TryFinally node""" + _astroid_fields = ('body', 'finalbody',) + body = None + finalbody = None + + def block_range(self, lineno): + """handle block line numbers range for try/finally statements""" + child = self.body[0] + # py2.5 try: except: finally: + if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno + and lineno > self.fromlineno and lineno <= child.tolineno): + return child.block_range(lineno) + return self._elsed_block_range(lineno, self.finalbody) + + +class Tuple(NodeNG, Instance, ParentAssignTypeMixin): + """class representing a Tuple node""" + _astroid_fields = ('elts',) + + def __init__(self, elts=None): + if elts is None: + self.elts = [] + else: + self.elts = [const_factory(e) for e in elts] + + def pytype(self): + return '%s.tuple' % BUILTINS + + def getitem(self, index, context=None): + return self.elts[index] + + def itered(self): + return self.elts + + +class UnaryOp(NodeNG): + """class representing an UnaryOp node""" + _astroid_fields = ('operand',) + operand = None + + +class While(BlockRangeMixIn, Statement): + """class representing a While node""" + _astroid_fields = ('test', 'body', 'orelse',) + test = None + body = None + orelse = None + + @cachedproperty + def blockstart_tolineno(self): + return self.test.tolineno + + def block_range(self, lineno): + """handle block line numbers range for for and while statements""" + return self. _elsed_block_range(lineno, self.orelse) + + +class With(BlockRangeMixIn, AssignTypeMixin, Statement): + """class representing a With node""" + _astroid_fields = ('items', 'body') + items = None + body = None + + @cachedproperty + def blockstart_tolineno(self): + return self.items[-1][0].tolineno + + def get_children(self): + for expr, var in self.items: + yield expr + if var: + yield var + for elt in self.body: + yield elt + +class Yield(NodeNG): + """class representing a Yield node""" + _astroid_fields = ('value',) + value = None + +class YieldFrom(Yield): + """ Class representing a YieldFrom node. """ + +# constants ############################################################## + +CONST_CLS = { + list: List, + tuple: Tuple, + dict: Dict, + set: Set, + type(None): Const, + } + +def _update_const_classes(): + """update constant classes, so the keys of CONST_CLS can be reused""" + klasses = (bool, int, float, complex, str) + if sys.version_info < (3, 0): + klasses += (unicode, long) + if sys.version_info >= (2, 6): + klasses += (bytes,) + for kls in klasses: + CONST_CLS[kls] = Const +_update_const_classes() + +def const_factory(value): + """return an astroid node for a python value""" + # XXX we should probably be stricter here and only consider stuff in + # CONST_CLS or do better treatment: in case where value is not in CONST_CLS, + # we should rather recall the builder on this value than returning an empty + # node (another option being that const_factory shouldn't be called with something + # not in CONST_CLS) + assert not isinstance(value, NodeNG) + try: + return CONST_CLS[value.__class__](value) + except (KeyError, AttributeError): + node = EmptyNode() + node.object = value + return node diff -Nru astroid-1.0.1/astroid/nodes.py astroid-1.3.8/astroid/nodes.py --- astroid-1.0.1/astroid/nodes.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/nodes.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,74 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +""" +on all nodes : + .is_statement, returning true if the node should be considered as a + statement node + .root(), returning the root node of the tree (i.e. a Module) + .previous_sibling(), returning previous sibling statement node + .next_sibling(), returning next sibling statement node + .statement(), returning the first parent node marked as statement node + .frame(), returning the first node defining a new local scope (i.e. + Module, Function or Class) + .set_local(name, node), define an identifier on the first parent frame, + with the node defining it. This is used by the astroid builder and should not + be used from out there. + +on From and Import : + .real_name(name), + + +""" +# pylint: disable=unused-import + +__docformat__ = "restructuredtext en" + +from astroid.node_classes import Arguments, AssAttr, Assert, Assign, \ + AssName, AugAssign, Backquote, BinOp, BoolOp, Break, CallFunc, Compare, \ + Comprehension, Const, Continue, Decorators, DelAttr, DelName, Delete, \ + Dict, Discard, Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, For, \ + From, Getattr, Global, If, IfExp, Import, Index, Keyword, \ + List, Name, Nonlocal, Pass, Print, Raise, Return, Set, Slice, Starred, Subscript, \ + TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, YieldFrom, \ + const_factory +from astroid.scoped_nodes import Module, GenExpr, Lambda, DictComp, \ + ListComp, SetComp, Function, Class + +ALL_NODE_CLASSES = ( + Arguments, AssAttr, Assert, Assign, AssName, AugAssign, + Backquote, BinOp, BoolOp, Break, + CallFunc, Class, Compare, Comprehension, Const, Continue, + Decorators, DelAttr, DelName, Delete, + Dict, DictComp, Discard, + Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, + For, From, Function, + Getattr, GenExpr, Global, + If, IfExp, Import, Index, + Keyword, + Lambda, List, ListComp, + Name, Nonlocal, + Module, + Pass, Print, + Raise, Return, + Set, SetComp, Slice, Starred, Subscript, + TryExcept, TryFinally, Tuple, + UnaryOp, + While, With, + Yield, YieldFrom + ) + diff -Nru astroid-1.0.1/astroid/__pkginfo__.py astroid-1.3.8/astroid/__pkginfo__.py --- astroid-1.0.1/astroid/__pkginfo__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/__pkginfo__.py 2015-08-02 19:37:10.000000000 +0000 @@ -0,0 +1,42 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""astroid packaging information""" +distname = 'astroid' + +modname = 'astroid' + +numversion = (1, 3, 8) +version = '.'.join([str(num) for num in numversion]) + +install_requires = ['logilab-common>=0.63.0', 'six'] + +license = 'LGPL' + +author = 'Logilab' +author_email = 'pylint-dev@lists.logilab.org' +mailinglist = "mailto://%s" % author_email +web = 'http://bitbucket.org/logilab/astroid' + +description = "A abstract syntax tree for Python with inference support." + +classifiers = ["Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Quality Assurance", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + ] diff -Nru astroid-1.0.1/astroid/protocols.py astroid-1.3.8/astroid/protocols.py --- astroid-1.0.1/astroid/protocols.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/protocols.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,415 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""this module contains a set of functions to handle python protocols for nodes +where it makes sense. +""" + +__doctype__ = "restructuredtext en" +import collections + +from astroid.exceptions import InferenceError, NoDefault, NotFoundError +from astroid.node_classes import unpack_infer +from astroid.bases import InferenceContext, copy_context, \ + raise_if_nothing_infered, yes_if_nothing_infered, Instance, YES +from astroid.nodes import const_factory +from astroid import nodes + +BIN_OP_METHOD = {'+': '__add__', + '-': '__sub__', + '/': '__div__', + '//': '__floordiv__', + '*': '__mul__', + '**': '__power__', + '%': '__mod__', + '&': '__and__', + '|': '__or__', + '^': '__xor__', + '<<': '__lshift__', + '>>': '__rshift__', + } + +UNARY_OP_METHOD = {'+': '__pos__', + '-': '__neg__', + '~': '__invert__', + 'not': None, # XXX not '__nonzero__' + } + +# unary operations ############################################################ + +def tl_infer_unary_op(self, operator): + if operator == 'not': + return const_factory(not bool(self.elts)) + raise TypeError() # XXX log unsupported operation +nodes.Tuple.infer_unary_op = tl_infer_unary_op +nodes.List.infer_unary_op = tl_infer_unary_op + + +def dict_infer_unary_op(self, operator): + if operator == 'not': + return const_factory(not bool(self.items)) + raise TypeError() # XXX log unsupported operation +nodes.Dict.infer_unary_op = dict_infer_unary_op + + +def const_infer_unary_op(self, operator): + if operator == 'not': + return const_factory(not self.value) + # XXX log potentially raised TypeError + elif operator == '+': + return const_factory(+self.value) + else: # operator == '-': + return const_factory(-self.value) +nodes.Const.infer_unary_op = const_infer_unary_op + + +# binary operations ########################################################### + +BIN_OP_IMPL = {'+': lambda a, b: a + b, + '-': lambda a, b: a - b, + '/': lambda a, b: a / b, + '//': lambda a, b: a // b, + '*': lambda a, b: a * b, + '**': lambda a, b: a ** b, + '%': lambda a, b: a % b, + '&': lambda a, b: a & b, + '|': lambda a, b: a | b, + '^': lambda a, b: a ^ b, + '<<': lambda a, b: a << b, + '>>': lambda a, b: a >> b, + } +for key, impl in list(BIN_OP_IMPL.items()): + BIN_OP_IMPL[key+'='] = impl + +def const_infer_binary_op(self, operator, other, context): + for other in other.infer(context): + if isinstance(other, nodes.Const): + try: + impl = BIN_OP_IMPL[operator] + + try: + yield const_factory(impl(self.value, other.value)) + except Exception: + # ArithmeticError is not enough: float >> float is a TypeError + # TODO : let pylint know about the problem + pass + except TypeError: + # XXX log TypeError + continue + elif other is YES: + yield other + else: + try: + for val in other.infer_binary_op(operator, self, context): + yield val + except AttributeError: + yield YES +nodes.Const.infer_binary_op = yes_if_nothing_infered(const_infer_binary_op) + + +def tl_infer_binary_op(self, operator, other, context): + for other in other.infer(context): + if isinstance(other, self.__class__) and operator == '+': + node = self.__class__() + elts = [n for elt in self.elts for n in elt.infer(context) + if not n is YES] + elts += [n for elt in other.elts for n in elt.infer(context) + if not n is YES] + node.elts = elts + yield node + elif isinstance(other, nodes.Const) and operator == '*': + if not isinstance(other.value, int): + yield YES + continue + node = self.__class__() + elts = [n for elt in self.elts for n in elt.infer(context) + if not n is YES] * other.value + node.elts = elts + yield node + elif isinstance(other, Instance) and not isinstance(other, nodes.Const): + yield YES + # XXX else log TypeError +nodes.Tuple.infer_binary_op = yes_if_nothing_infered(tl_infer_binary_op) +nodes.List.infer_binary_op = yes_if_nothing_infered(tl_infer_binary_op) + + +def dict_infer_binary_op(self, operator, other, context): + for other in other.infer(context): + if isinstance(other, Instance) and isinstance(other._proxied, nodes.Class): + yield YES + # XXX else log TypeError +nodes.Dict.infer_binary_op = yes_if_nothing_infered(dict_infer_binary_op) + +def instance_infer_binary_op(self, operator, other, context): + try: + methods = self.getattr(BIN_OP_METHOD[operator]) + except (NotFoundError, KeyError): + # Unknown operator + yield YES + else: + for method in methods: + if not isinstance(method, nodes.Function): + continue + for result in method.infer_call_result(self, context): + if result is not YES: + yield result + # We are interested only in the first infered method, + # don't go looking in the rest of the methods of the ancestors. + break + +Instance.infer_binary_op = yes_if_nothing_infered(instance_infer_binary_op) + + +# assignment ################################################################## + +"""the assigned_stmts method is responsible to return the assigned statement +(e.g. not inferred) according to the assignment type. + +The `asspath` argument is used to record the lhs path of the original node. +For instance if we want assigned statements for 'c' in 'a, (b,c)', asspath +will be [1, 1] once arrived to the Assign node. + +The `context` argument is the current inference context which should be given +to any intermediary inference necessary. +""" + +def _resolve_looppart(parts, asspath, context): + """recursive function to resolve multiple assignments on loops""" + asspath = asspath[:] + index = asspath.pop(0) + for part in parts: + if part is YES: + continue + # XXX handle __iter__ and log potentially detected errors + if not hasattr(part, 'itered'): + continue + try: + itered = part.itered() + except TypeError: + continue # XXX log error + for stmt in itered: + try: + assigned = stmt.getitem(index, context) + except (AttributeError, IndexError): + continue + except TypeError: # stmt is unsubscriptable Const + continue + if not asspath: + # we achieved to resolved the assignment path, + # don't infer the last part + yield assigned + elif assigned is YES: + break + else: + # we are not yet on the last part of the path + # search on each possibly inferred value + try: + for infered in _resolve_looppart(assigned.infer(context), + asspath, context): + yield infered + except InferenceError: + break + + +def for_assigned_stmts(self, node, context=None, asspath=None): + if asspath is None: + for lst in self.iter.infer(context): + if isinstance(lst, (nodes.Tuple, nodes.List)): + for item in lst.elts: + yield item + else: + for infered in _resolve_looppart(self.iter.infer(context), + asspath, context): + yield infered + +nodes.For.assigned_stmts = raise_if_nothing_infered(for_assigned_stmts) +nodes.Comprehension.assigned_stmts = raise_if_nothing_infered(for_assigned_stmts) + + +def mulass_assigned_stmts(self, node, context=None, asspath=None): + if asspath is None: + asspath = [] + asspath.insert(0, self.elts.index(node)) + return self.parent.assigned_stmts(self, context, asspath) +nodes.Tuple.assigned_stmts = mulass_assigned_stmts +nodes.List.assigned_stmts = mulass_assigned_stmts + + +def assend_assigned_stmts(self, context=None): + return self.parent.assigned_stmts(self, context=context) +nodes.AssName.assigned_stmts = assend_assigned_stmts +nodes.AssAttr.assigned_stmts = assend_assigned_stmts + + +def _arguments_infer_argname(self, name, context): + # arguments information may be missing, in which case we can't do anything + # more + if not (self.args or self.vararg or self.kwarg): + yield YES + return + # first argument of instance/class method + if self.args and getattr(self.args[0], 'name', None) == name: + functype = self.parent.type + if functype == 'method': + yield Instance(self.parent.parent.frame()) + return + if functype == 'classmethod': + yield self.parent.parent.frame() + return + if name == self.vararg: + vararg = const_factory(()) + vararg.parent = self + yield vararg + return + if name == self.kwarg: + kwarg = const_factory({}) + kwarg.parent = self + yield kwarg + return + # if there is a default value, yield it. And then yield YES to reflect + # we can't guess given argument value + try: + context = copy_context(context) + for infered in self.default_value(name).infer(context): + yield infered + yield YES + except NoDefault: + yield YES + + +def arguments_assigned_stmts(self, node, context, asspath=None): + if context.callcontext: + # reset call context/name + callcontext = context.callcontext + context = copy_context(context) + context.callcontext = None + return callcontext.infer_argument(self.parent, node.name, context) + return _arguments_infer_argname(self, node.name, context) +nodes.Arguments.assigned_stmts = arguments_assigned_stmts + + +def assign_assigned_stmts(self, node, context=None, asspath=None): + if not asspath: + yield self.value + return + for infered in _resolve_asspart(self.value.infer(context), asspath, context): + yield infered +nodes.Assign.assigned_stmts = raise_if_nothing_infered(assign_assigned_stmts) +nodes.AugAssign.assigned_stmts = raise_if_nothing_infered(assign_assigned_stmts) + + +def _resolve_asspart(parts, asspath, context): + """recursive function to resolve multiple assignments""" + asspath = asspath[:] + index = asspath.pop(0) + for part in parts: + if hasattr(part, 'getitem'): + try: + assigned = part.getitem(index, context) + # XXX raise a specific exception to avoid potential hiding of + # unexpected exception ? + except (TypeError, IndexError): + return + if not asspath: + # we achieved to resolved the assignment path, don't infer the + # last part + yield assigned + elif assigned is YES: + return + else: + # we are not yet on the last part of the path search on each + # possibly inferred value + try: + for infered in _resolve_asspart(assigned.infer(context), + asspath, context): + yield infered + except InferenceError: + return + + +def excepthandler_assigned_stmts(self, node, context=None, asspath=None): + for assigned in unpack_infer(self.type): + if isinstance(assigned, nodes.Class): + assigned = Instance(assigned) + yield assigned +nodes.ExceptHandler.assigned_stmts = raise_if_nothing_infered(excepthandler_assigned_stmts) + + +def with_assigned_stmts(self, node, context=None, asspath=None): + if asspath is None: + for _, vars in self.items: + if vars is None: + continue + for lst in vars.infer(context): + if isinstance(lst, (nodes.Tuple, nodes.List)): + for item in lst.nodes: + yield item +nodes.With.assigned_stmts = raise_if_nothing_infered(with_assigned_stmts) + + +def starred_assigned_stmts(self, node=None, context=None, asspath=None): + stmt = self.statement() + if not isinstance(stmt, (nodes.Assign, nodes.For)): + raise InferenceError() + + if isinstance(stmt, nodes.Assign): + value = stmt.value + lhs = stmt.targets[0] + + if sum(1 for node in lhs.nodes_of_class(nodes.Starred)) > 1: + # Too many starred arguments in the expression. + raise InferenceError() + + if context is None: + context = InferenceContext() + try: + rhs = next(value.infer(context)) + except InferenceError: + yield YES + return + if rhs is YES or not hasattr(rhs, 'elts'): + # Not interested in inferred values without elts. + yield YES + return + + elts = collections.deque(rhs.elts[:]) + if len(lhs.elts) > len(rhs.elts): + # a, *b, c = (1, 2) + raise InferenceError() + + # Unpack iteratively the values from the rhs of the assignment, + # until the find the starred node. What will remain will + # be the list of values which the Starred node will represent + # This is done in two steps, from left to right to remove + # anything before the starred node and from right to left + # to remvoe anything after the starred node. + + for index, node in enumerate(lhs.elts): + if not isinstance(node, nodes.Starred): + elts.popleft() + continue + lhs_elts = collections.deque(reversed(lhs.elts[index:])) + for node in lhs_elts: + if not isinstance(node, nodes.Starred): + elts.pop() + continue + # We're done + for elt in elts: + yield elt + break + +nodes.Starred.assigned_stmts = starred_assigned_stmts diff -Nru astroid-1.0.1/astroid/raw_building.py astroid-1.3.8/astroid/raw_building.py --- astroid-1.0.1/astroid/raw_building.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/raw_building.py 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,366 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""this module contains a set of functions to create astroid trees from scratch +(build_* functions) or from living object (object_build_* functions) +""" + +__docformat__ = "restructuredtext en" + +import sys +from os.path import abspath +from inspect import (getargspec, isdatadescriptor, isfunction, ismethod, + ismethoddescriptor, isclass, isbuiltin, ismodule) +import six + +from astroid.node_classes import CONST_CLS +from astroid.nodes import (Module, Class, Const, const_factory, From, + Function, EmptyNode, Name, Arguments) +from astroid.bases import BUILTINS, Generator +from astroid.manager import AstroidManager +MANAGER = AstroidManager() + +_CONSTANTS = tuple(CONST_CLS) # the keys of CONST_CLS eg python builtin types + +def _io_discrepancy(member): + # _io module names itself `io`: http://bugs.python.org/issue18602 + member_self = getattr(member, '__self__', None) + return (member_self and + ismodule(member_self) and + member_self.__name__ == '_io' and + member.__module__ == 'io') + +def _attach_local_node(parent, node, name): + node.name = name # needed by add_local_node + parent.add_local_node(node) + +_marker = object() + +def attach_dummy_node(node, name, object=_marker): + """create a dummy node and register it in the locals of the given + node with the specified name + """ + enode = EmptyNode() + enode.object = object + _attach_local_node(node, enode, name) + +def _has_underlying_object(self): + return hasattr(self, 'object') and self.object is not _marker + +EmptyNode.has_underlying_object = _has_underlying_object + +def attach_const_node(node, name, value): + """create a Const node and register it in the locals of the given + node with the specified name + """ + if not name in node.special_attributes: + _attach_local_node(node, const_factory(value), name) + +def attach_import_node(node, modname, membername): + """create a From node and register it in the locals of the given + node with the specified name + """ + from_node = From(modname, [(membername, None)]) + _attach_local_node(node, from_node, membername) + + +def build_module(name, doc=None): + """create and initialize a astroid Module node""" + node = Module(name, doc, pure_python=False) + node.package = False + node.parent = None + return node + +def build_class(name, basenames=(), doc=None): + """create and initialize a astroid Class node""" + node = Class(name, doc) + for base in basenames: + basenode = Name() + basenode.name = base + node.bases.append(basenode) + basenode.parent = node + return node + +def build_function(name, args=None, defaults=None, flag=0, doc=None): + """create and initialize a astroid Function node""" + args, defaults = args or [], defaults or [] + # first argument is now a list of decorators + func = Function(name, doc) + func.args = argsnode = Arguments() + argsnode.args = [] + for arg in args: + argsnode.args.append(Name()) + argsnode.args[-1].name = arg + argsnode.args[-1].parent = argsnode + argsnode.defaults = [] + for default in defaults: + argsnode.defaults.append(const_factory(default)) + argsnode.defaults[-1].parent = argsnode + argsnode.kwarg = None + argsnode.vararg = None + argsnode.parent = func + if args: + register_arguments(func) + return func + + +def build_from_import(fromname, names): + """create and initialize an astroid From import statement""" + return From(fromname, [(name, None) for name in names]) + +def register_arguments(func, args=None): + """add given arguments to local + + args is a list that may contains nested lists + (i.e. def func(a, (b, c, d)): ...) + """ + if args is None: + args = func.args.args + if func.args.vararg: + func.set_local(func.args.vararg, func.args) + if func.args.kwarg: + func.set_local(func.args.kwarg, func.args) + for arg in args: + if isinstance(arg, Name): + func.set_local(arg.name, arg) + else: + register_arguments(func, arg.elts) + +def object_build_class(node, member, localname): + """create astroid for a living class object""" + basenames = [base.__name__ for base in member.__bases__] + return _base_class_object_build(node, member, basenames, + localname=localname) + +def object_build_function(node, member, localname): + """create astroid for a living function object""" + args, varargs, varkw, defaults = getargspec(member) + if varargs is not None: + args.append(varargs) + if varkw is not None: + args.append(varkw) + func = build_function(getattr(member, '__name__', None) or localname, args, + defaults, six.get_function_code(member).co_flags, member.__doc__) + node.add_local_node(func, localname) + +def object_build_datadescriptor(node, member, name): + """create astroid for a living data descriptor object""" + return _base_class_object_build(node, member, [], name) + +def object_build_methoddescriptor(node, member, localname): + """create astroid for a living method descriptor object""" + # FIXME get arguments ? + func = build_function(getattr(member, '__name__', None) or localname, + doc=member.__doc__) + # set node's arguments to None to notice that we have no information, not + # and empty argument list + func.args.args = None + node.add_local_node(func, localname) + +def _base_class_object_build(node, member, basenames, name=None, localname=None): + """create astroid for a living class object, with a given set of base names + (e.g. ancestors) + """ + klass = build_class(name or getattr(member, '__name__', None) or localname, + basenames, member.__doc__) + klass._newstyle = isinstance(member, type) + node.add_local_node(klass, localname) + try: + # limit the instantiation trick since it's too dangerous + # (such as infinite test execution...) + # this at least resolves common case such as Exception.args, + # OSError.errno + if issubclass(member, Exception): + instdict = member().__dict__ + else: + raise TypeError + except: + pass + else: + for name, obj in instdict.items(): + valnode = EmptyNode() + valnode.object = obj + valnode.parent = klass + valnode.lineno = 1 + klass.instance_attrs[name] = [valnode] + return klass + + + + +class InspectBuilder(object): + """class for building nodes from living object + + this is actually a really minimal representation, including only Module, + Function and Class nodes and some others as guessed. + """ + + # astroid from living objects ############################################### + + def __init__(self): + self._done = {} + self._module = None + + def inspect_build(self, module, modname=None, path=None): + """build astroid from a living module (i.e. using inspect) + this is used when there is no python source code available (either + because it's a built-in module or because the .py is not available) + """ + self._module = module + if modname is None: + modname = module.__name__ + try: + node = build_module(modname, module.__doc__) + except AttributeError: + # in jython, java modules have no __doc__ (see #109562) + node = build_module(modname) + node.file = node.path = path and abspath(path) or path + node.name = modname + MANAGER.cache_module(node) + node.package = hasattr(module, '__path__') + self._done = {} + self.object_build(node, module) + return node + + def object_build(self, node, obj): + """recursive method which create a partial ast from real objects + (only function, class, and method are handled) + """ + if obj in self._done: + return self._done[obj] + self._done[obj] = node + for name in dir(obj): + try: + member = getattr(obj, name) + except AttributeError: + # damned ExtensionClass.Base, I know you're there ! + attach_dummy_node(node, name) + continue + if ismethod(member): + member = six.get_method_function(member) + if isfunction(member): + # verify this is not an imported function + filename = getattr(six.get_function_code(member), + 'co_filename', None) + if filename is None: + assert isinstance(member, object) + object_build_methoddescriptor(node, member, name) + elif filename != getattr(self._module, '__file__', None): + attach_dummy_node(node, name, member) + else: + object_build_function(node, member, name) + elif isbuiltin(member): + if (not _io_discrepancy(member) and + self.imported_member(node, member, name)): + continue + object_build_methoddescriptor(node, member, name) + elif isclass(member): + if self.imported_member(node, member, name): + continue + if member in self._done: + class_node = self._done[member] + if not class_node in node.locals.get(name, ()): + node.add_local_node(class_node, name) + else: + class_node = object_build_class(node, member, name) + # recursion + self.object_build(class_node, member) + if name == '__class__' and class_node.parent is None: + class_node.parent = self._done[self._module] + elif ismethoddescriptor(member): + assert isinstance(member, object) + object_build_methoddescriptor(node, member, name) + elif isdatadescriptor(member): + assert isinstance(member, object) + object_build_datadescriptor(node, member, name) + elif type(member) in _CONSTANTS: + attach_const_node(node, name, member) + else: + # create an empty node so that the name is actually defined + attach_dummy_node(node, name, member) + + def imported_member(self, node, member, name): + """verify this is not an imported class or handle it""" + # /!\ some classes like ExtensionClass doesn't have a __module__ + # attribute ! Also, this may trigger an exception on badly built module + # (see http://www.logilab.org/ticket/57299 for instance) + try: + modname = getattr(member, '__module__', None) + except: + # XXX use logging + print('unexpected error while building astroid from living object') + import traceback + traceback.print_exc() + modname = None + if modname is None: + if name in ('__new__', '__subclasshook__'): + # Python 2.5.1 (r251:54863, Sep 1 2010, 22:03:14) + # >>> print object.__new__.__module__ + # None + modname = BUILTINS + else: + attach_dummy_node(node, name, member) + return True + if {'gtk': 'gtk._gtk'}.get(modname, modname) != self._module.__name__: + # check if it sounds valid and then add an import node, else use a + # dummy node + try: + getattr(sys.modules[modname], name) + except (KeyError, AttributeError): + attach_dummy_node(node, name, member) + else: + attach_import_node(node, modname, name) + return True + return False + + +### astroid bootstrapping ###################################################### +Astroid_BUILDER = InspectBuilder() + +_CONST_PROXY = {} +def _astroid_bootstrapping(astroid_builtin=None): + """astroid boot strapping the builtins module""" + # this boot strapping is necessary since we need the Const nodes to + # inspect_build builtins, and then we can proxy Const + if astroid_builtin is None: + from logilab.common.compat import builtins + astroid_builtin = Astroid_BUILDER.inspect_build(builtins) + + for cls, node_cls in CONST_CLS.items(): + if cls is type(None): + proxy = build_class('NoneType') + proxy.parent = astroid_builtin + else: + proxy = astroid_builtin.getattr(cls.__name__)[0] + if cls in (dict, list, set, tuple): + node_cls._proxied = proxy + else: + _CONST_PROXY[cls] = proxy + +_astroid_bootstrapping() + +# TODO : find a nicer way to handle this situation; +# However __proxied introduced an +# infinite recursion (see https://bugs.launchpad.net/pylint/+bug/456870) +def _set_proxied(const): + return _CONST_PROXY[const.value.__class__] +Const._proxied = property(_set_proxied) + +from types import GeneratorType +Generator._proxied = Class(GeneratorType.__name__, GeneratorType.__doc__) +Astroid_BUILDER.object_build(Generator._proxied, GeneratorType) + diff -Nru astroid-1.0.1/astroid/rebuilder.py astroid-1.3.8/astroid/rebuilder.py --- astroid-1.0.1/astroid/rebuilder.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/rebuilder.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,926 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""this module contains utilities for rebuilding a _ast tree in +order to get a single Astroid representation +""" + +import sys +from _ast import ( + Expr as Discard, Str, + # binary operators + Add, BinOp, Div, FloorDiv, Mod, Mult, Pow, Sub, BitAnd, BitOr, BitXor, + LShift, RShift, + # logical operators + And, Or, + # unary operators + UAdd, USub, Not, Invert, + # comparison operators + Eq, Gt, GtE, In, Is, IsNot, Lt, LtE, NotEq, NotIn, + ) + +from astroid import nodes as new +from astroid import astpeephole + + +_BIN_OP_CLASSES = {Add: '+', + BitAnd: '&', + BitOr: '|', + BitXor: '^', + Div: '/', + FloorDiv: '//', + Mod: '%', + Mult: '*', + Pow: '**', + Sub: '-', + LShift: '<<', + RShift: '>>', + } + +_BOOL_OP_CLASSES = {And: 'and', + Or: 'or', + } + +_UNARY_OP_CLASSES = {UAdd: '+', + USub: '-', + Not: 'not', + Invert: '~', + } + +_CMP_OP_CLASSES = {Eq: '==', + Gt: '>', + GtE: '>=', + In: 'in', + Is: 'is', + IsNot: 'is not', + Lt: '<', + LtE: '<=', + NotEq: '!=', + NotIn: 'not in', + } + +CONST_NAME_TRANSFORMS = {'None': None, + 'True': True, + 'False': False, + } + +REDIRECT = {'arguments': 'Arguments', + 'Attribute': 'Getattr', + 'comprehension': 'Comprehension', + 'Call': 'CallFunc', + 'ClassDef': 'Class', + "ListCompFor": 'Comprehension', + "GenExprFor": 'Comprehension', + 'excepthandler': 'ExceptHandler', + 'Expr': 'Discard', + 'FunctionDef': 'Function', + 'GeneratorExp': 'GenExpr', + 'ImportFrom': 'From', + 'keyword': 'Keyword', + 'Repr': 'Backquote', + } +PY3K = sys.version_info >= (3, 0) +PY34 = sys.version_info >= (3, 4) + +def _init_set_doc(node, newnode): + newnode.doc = None + try: + if isinstance(node.body[0], Discard) and isinstance(node.body[0].value, Str): + newnode.doc = node.body[0].value.s + node.body = node.body[1:] + + except IndexError: + pass # ast built from scratch + +def _lineno_parent(oldnode, newnode, parent): + newnode.parent = parent + newnode.lineno = oldnode.lineno + newnode.col_offset = oldnode.col_offset + +def _set_infos(oldnode, newnode, parent): + newnode.parent = parent + if hasattr(oldnode, 'lineno'): + newnode.lineno = oldnode.lineno + if hasattr(oldnode, 'col_offset'): + newnode.col_offset = oldnode.col_offset + +def _create_yield_node(node, parent, rebuilder, factory): + newnode = factory() + _lineno_parent(node, newnode, parent) + if node.value is not None: + newnode.value = rebuilder.visit(node.value, newnode) + return newnode + + +class TreeRebuilder(object): + """Rebuilds the _ast tree to become an Astroid tree""" + + def __init__(self, manager): + self._manager = manager + self.asscontext = None + self._global_names = [] + self._from_nodes = [] + self._delayed_assattr = [] + self._visit_meths = {} + self._transform = manager.transform + self._peepholer = astpeephole.ASTPeepholeOptimizer() + + def visit_module(self, node, modname, modpath, package): + """visit a Module node by returning a fresh instance of it""" + newnode = new.Module(modname, None) + newnode.package = package + newnode.parent = None + _init_set_doc(node, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.file = newnode.path = modpath + return self._transform(newnode) + + def visit(self, node, parent): + cls = node.__class__ + if cls in self._visit_meths: + visit_method = self._visit_meths[cls] + else: + cls_name = cls.__name__ + visit_name = 'visit_' + REDIRECT.get(cls_name, cls_name).lower() + visit_method = getattr(self, visit_name) + self._visit_meths[cls] = visit_method + return self._transform(visit_method(node, parent)) + + def _save_assignment(self, node, name=None): + """save assignement situation since node.parent is not available yet""" + if self._global_names and node.name in self._global_names[-1]: + node.root().set_local(node.name, node) + else: + node.parent.set_local(node.name, node) + + + def visit_arguments(self, node, parent): + """visit a Arguments node by returning a fresh instance of it""" + newnode = new.Arguments() + newnode.parent = parent + self.asscontext = "Ass" + 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 = [] + vararg, kwarg = node.vararg, node.kwarg + # change added in 82732 (7c5c678e4164), vararg and kwarg + # are instances of `_ast.arg`, not strings + if vararg: + if PY34: + if vararg.annotation: + newnode.varargannotation = self.visit(vararg.annotation, + newnode) + vararg = vararg.arg + elif PY3K and node.varargannotation: + newnode.varargannotation = self.visit(node.varargannotation, + newnode) + if kwarg: + if PY34: + if kwarg.annotation: + newnode.kwargannotation = self.visit(kwarg.annotation, + newnode) + kwarg = kwarg.arg + elif PY3K: + if node.kwargannotation: + newnode.kwargannotation = self.visit(node.kwargannotation, + newnode) + newnode.vararg = vararg + newnode.kwarg = kwarg + # save argument names in locals: + if vararg: + newnode.parent.set_local(vararg, newnode) + if kwarg: + newnode.parent.set_local(kwarg, newnode) + return newnode + + def visit_assattr(self, node, parent): + """visit a AssAttr node by returning a fresh instance of it""" + assc, self.asscontext = self.asscontext, None + newnode = new.AssAttr() + _lineno_parent(node, newnode, parent) + newnode.expr = self.visit(node.expr, newnode) + self.asscontext = assc + self._delayed_assattr.append(newnode) + return newnode + + def visit_assert(self, node, parent): + """visit a Assert node by returning a fresh instance of it""" + newnode = new.Assert() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + if node.msg is not None: + newnode.fail = self.visit(node.msg, newnode) + return newnode + + def visit_assign(self, node, parent): + """visit a Assign node by returning a fresh instance of it""" + newnode = new.Assign() + _lineno_parent(node, newnode, parent) + self.asscontext = "Ass" + newnode.targets = [self.visit(child, newnode) for child in node.targets] + self.asscontext = None + newnode.value = self.visit(node.value, newnode) + # set some function or metaclass infos XXX explain ? + klass = newnode.parent.frame() + if (isinstance(klass, new.Class) + and isinstance(newnode.value, new.CallFunc) + and isinstance(newnode.value.func, new.Name)): + func_name = newnode.value.func.name + for ass_node in newnode.targets: + try: + meth = klass[ass_node.name] + if isinstance(meth, new.Function): + if func_name in ('classmethod', 'staticmethod'): + meth.type = func_name + elif func_name == 'classproperty': # see lgc.decorators + meth.type = 'classmethod' + meth.extra_decorators.append(newnode.value) + except (AttributeError, KeyError): + continue + return newnode + + def visit_assname(self, node, parent, node_name=None): + '''visit a node and return a AssName node''' + newnode = new.AssName() + _set_infos(node, newnode, parent) + newnode.name = node_name + self._save_assignment(newnode) + return newnode + + def visit_augassign(self, node, parent): + """visit a AugAssign node by returning a fresh instance of it""" + newnode = new.AugAssign() + _lineno_parent(node, newnode, parent) + newnode.op = _BIN_OP_CLASSES[node.op.__class__] + "=" + self.asscontext = "Ass" + newnode.target = self.visit(node.target, newnode) + self.asscontext = None + newnode.value = self.visit(node.value, newnode) + return newnode + + def visit_backquote(self, node, parent): + """visit a Backquote node by returning a fresh instance of it""" + newnode = new.Backquote() + _lineno_parent(node, newnode, parent) + newnode.value = self.visit(node.value, newnode) + return newnode + + def visit_binop(self, node, parent): + """visit a BinOp node by returning a fresh instance of it""" + if isinstance(node.left, BinOp) and self._manager.optimize_ast: + # Optimize BinOp operations in order to remove + # redundant recursion. For instance, if the + # following code is parsed in order to obtain + # its ast, then the rebuilder will fail with an + # infinite recursion, the same will happen with the + # inference engine as well. There's no need to hold + # so many objects for the BinOp if they can be reduced + # to something else (also, the optimization + # might handle only Const binops, which isn't a big + # problem for the correctness of the program). + # + # ("a" + "b" + # one thousand more + "c") + newnode = self._peepholer.optimize_binop(node) + if newnode: + _lineno_parent(node, newnode, parent) + return newnode + + newnode = new.BinOp() + _lineno_parent(node, newnode, parent) + newnode.left = self.visit(node.left, newnode) + newnode.right = self.visit(node.right, newnode) + newnode.op = _BIN_OP_CLASSES[node.op.__class__] + return newnode + + def visit_boolop(self, node, parent): + """visit a BoolOp node by returning a fresh instance of it""" + newnode = new.BoolOp() + _lineno_parent(node, newnode, parent) + newnode.values = [self.visit(child, newnode) for child in node.values] + newnode.op = _BOOL_OP_CLASSES[node.op.__class__] + return newnode + + def visit_break(self, node, parent): + """visit a Break node by returning a fresh instance of it""" + newnode = new.Break() + _set_infos(node, newnode, parent) + return newnode + + def visit_callfunc(self, node, parent): + """visit a CallFunc node by returning a fresh instance of it""" + newnode = new.CallFunc() + _lineno_parent(node, newnode, parent) + newnode.func = self.visit(node.func, newnode) + newnode.args = [self.visit(child, newnode) for child in node.args] + if node.starargs is not None: + newnode.starargs = self.visit(node.starargs, newnode) + if node.kwargs is not None: + newnode.kwargs = self.visit(node.kwargs, newnode) + for child in node.keywords: + newnode.args.append(self.visit(child, newnode)) + return newnode + + def visit_class(self, node, parent): + """visit a Class node to become astroid""" + newnode = new.Class(node.name, None) + _lineno_parent(node, newnode, parent) + _init_set_doc(node, newnode) + newnode.bases = [self.visit(child, newnode) for child in node.bases] + newnode.body = [self.visit(child, newnode) for child in node.body] + if 'decorator_list' in node._fields and node.decorator_list:# py >= 2.6 + newnode.decorators = self.visit_decorators(node, newnode) + newnode.parent.frame().set_local(newnode.name, newnode) + return newnode + + def visit_const(self, node, parent): + """visit a Const node by returning a fresh instance of it""" + newnode = new.Const(node.value) + _set_infos(node, newnode, parent) + return newnode + + def visit_continue(self, node, parent): + """visit a Continue node by returning a fresh instance of it""" + newnode = new.Continue() + _set_infos(node, newnode, parent) + return newnode + + def visit_compare(self, node, parent): + """visit a Compare node by returning a fresh instance of it""" + newnode = new.Compare() + _lineno_parent(node, newnode, parent) + newnode.left = self.visit(node.left, newnode) + newnode.ops = [(_CMP_OP_CLASSES[op.__class__], self.visit(expr, newnode)) + for (op, expr) in zip(node.ops, node.comparators)] + return newnode + + def visit_comprehension(self, node, parent): + """visit a Comprehension node by returning a fresh instance of it""" + newnode = new.Comprehension() + newnode.parent = parent + self.asscontext = "Ass" + newnode.target = self.visit(node.target, newnode) + self.asscontext = None + newnode.iter = self.visit(node.iter, newnode) + newnode.ifs = [self.visit(child, newnode) for child in node.ifs] + return newnode + + def visit_decorators(self, node, parent): + """visit a Decorators node by returning a fresh instance of it""" + # /!\ node is actually a _ast.Function node while + # parent is a astroid.nodes.Function node + newnode = new.Decorators() + _lineno_parent(node, newnode, parent) + if 'decorators' in node._fields: # py < 2.6, i.e. 2.5 + decorators = node.decorators + else: + decorators = node.decorator_list + newnode.nodes = [self.visit(child, newnode) for child in decorators] + return newnode + + def visit_delete(self, node, parent): + """visit a Delete node by returning a fresh instance of it""" + newnode = new.Delete() + _lineno_parent(node, newnode, parent) + self.asscontext = "Del" + newnode.targets = [self.visit(child, newnode) for child in node.targets] + self.asscontext = None + return newnode + + def visit_dict(self, node, parent): + """visit a Dict node by returning a fresh instance of it""" + newnode = new.Dict() + _lineno_parent(node, newnode, parent) + newnode.items = [(self.visit(key, newnode), self.visit(value, newnode)) + for key, value in zip(node.keys, node.values)] + return newnode + + def visit_dictcomp(self, node, parent): + """visit a DictComp node by returning a fresh instance of it""" + newnode = new.DictComp() + _lineno_parent(node, newnode, parent) + newnode.key = self.visit(node.key, newnode) + newnode.value = self.visit(node.value, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + return newnode + + def visit_discard(self, node, parent): + """visit a Discard node by returning a fresh instance of it""" + newnode = new.Discard() + _lineno_parent(node, newnode, parent) + newnode.value = self.visit(node.value, newnode) + return newnode + + def visit_ellipsis(self, node, parent): + """visit an Ellipsis node by returning a fresh instance of it""" + newnode = new.Ellipsis() + _set_infos(node, newnode, parent) + return newnode + + def visit_emptynode(self, node, parent): + """visit an EmptyNode node by returning a fresh instance of it""" + newnode = new.EmptyNode() + _set_infos(node, newnode, parent) + return newnode + + def visit_excepthandler(self, node, parent): + """visit an ExceptHandler node by returning a fresh instance of it""" + newnode = new.ExceptHandler() + _lineno_parent(node, newnode, parent) + if node.type is not None: + newnode.type = self.visit(node.type, newnode) + if node.name is not None: + # /!\ node.name can be a tuple + self.asscontext = "Ass" + newnode.name = self.visit(node.name, newnode) + self.asscontext = None + newnode.body = [self.visit(child, newnode) for child in node.body] + return newnode + + def visit_exec(self, node, parent): + """visit an Exec node by returning a fresh instance of it""" + newnode = new.Exec() + _lineno_parent(node, newnode, parent) + newnode.expr = self.visit(node.body, newnode) + if node.globals is not None: + newnode.globals = self.visit(node.globals, newnode) + if node.locals is not None: + newnode.locals = self.visit(node.locals, newnode) + return newnode + + def visit_extslice(self, node, parent): + """visit an ExtSlice node by returning a fresh instance of it""" + newnode = new.ExtSlice() + newnode.parent = parent + newnode.dims = [self.visit(dim, newnode) for dim in node.dims] + return newnode + + def visit_for(self, node, parent): + """visit a For node by returning a fresh instance of it""" + newnode = new.For() + _lineno_parent(node, newnode, parent) + self.asscontext = "Ass" + newnode.target = self.visit(node.target, newnode) + self.asscontext = None + newnode.iter = self.visit(node.iter, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + return newnode + + def visit_from(self, node, parent): + """visit a From node by returning a fresh instance of it""" + names = [(alias.name, alias.asname) for alias in node.names] + newnode = new.From(node.module or '', names, node.level or None) + _set_infos(node, newnode, parent) + # store From names to add them to locals after building + self._from_nodes.append(newnode) + return newnode + + def visit_function(self, node, parent): + """visit an Function node to become astroid""" + self._global_names.append({}) + newnode = new.Function(node.name, None) + _lineno_parent(node, newnode, parent) + _init_set_doc(node, newnode) + newnode.args = self.visit(node.args, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + if 'decorators' in node._fields: # py < 2.6 + attr = 'decorators' + else: + attr = 'decorator_list' + decorators = getattr(node, attr) + if decorators: + newnode.decorators = self.visit_decorators(node, newnode) + if PY3K and node.returns: + newnode.returns = self.visit(node.returns, newnode) + self._global_names.pop() + frame = newnode.parent.frame() + if isinstance(frame, new.Class): + if newnode.name == '__new__': + newnode._type = 'classmethod' + else: + newnode._type = 'method' + if newnode.decorators is not None: + for decorator_expr in newnode.decorators.nodes: + if isinstance(decorator_expr, new.Name): + if decorator_expr.name in ('classmethod', 'staticmethod'): + newnode._type = decorator_expr.name + elif decorator_expr.name == 'classproperty': + newnode._type = 'classmethod' + frame.set_local(newnode.name, newnode) + return newnode + + def visit_genexpr(self, node, parent): + """visit a GenExpr node by returning a fresh instance of it""" + newnode = new.GenExpr() + _lineno_parent(node, newnode, parent) + newnode.elt = self.visit(node.elt, newnode) + newnode.generators = [self.visit(child, newnode) for child in node.generators] + return newnode + + def visit_getattr(self, node, parent): + """visit a Getattr node by returning a fresh instance of it""" + if self.asscontext == "Del": + # FIXME : maybe we should reintroduce and visit_delattr ? + # for instance, deactivating asscontext + newnode = new.DelAttr() + elif self.asscontext == "Ass": + # FIXME : maybe we should call visit_assattr ? + newnode = new.AssAttr() + self._delayed_assattr.append(newnode) + else: + newnode = new.Getattr() + _lineno_parent(node, newnode, parent) + asscontext, self.asscontext = self.asscontext, None + newnode.expr = self.visit(node.value, newnode) + self.asscontext = asscontext + newnode.attrname = node.attr + return newnode + + def visit_global(self, node, parent): + """visit an Global node to become astroid""" + newnode = new.Global(node.names) + _set_infos(node, newnode, parent) + if self._global_names: # global at the module level, no effect + for name in node.names: + self._global_names[-1].setdefault(name, []).append(newnode) + return newnode + + def visit_if(self, node, parent): + """visit a If node by returning a fresh instance of it""" + newnode = new.If() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + return newnode + + def visit_ifexp(self, node, parent): + """visit a IfExp node by returning a fresh instance of it""" + newnode = new.IfExp() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + newnode.body = self.visit(node.body, newnode) + newnode.orelse = self.visit(node.orelse, newnode) + return newnode + + def visit_import(self, node, parent): + """visit a Import node by returning a fresh instance of it""" + newnode = new.Import() + _set_infos(node, newnode, parent) + newnode.names = [(alias.name, alias.asname) for alias in node.names] + # save import names in parent's locals: + for (name, asname) in newnode.names: + name = asname or name + newnode.parent.set_local(name.split('.')[0], newnode) + return newnode + + def visit_index(self, node, parent): + """visit a Index node by returning a fresh instance of it""" + newnode = new.Index() + newnode.parent = parent + newnode.value = self.visit(node.value, newnode) + return newnode + + def visit_keyword(self, node, parent): + """visit a Keyword node by returning a fresh instance of it""" + newnode = new.Keyword() + newnode.parent = parent + newnode.arg = node.arg + newnode.value = self.visit(node.value, newnode) + return newnode + + def visit_lambda(self, node, parent): + """visit a Lambda node by returning a fresh instance of it""" + newnode = new.Lambda() + _lineno_parent(node, newnode, parent) + newnode.args = self.visit(node.args, newnode) + newnode.body = self.visit(node.body, newnode) + return newnode + + def visit_list(self, node, parent): + """visit a List node by returning a fresh instance of it""" + newnode = new.List() + _lineno_parent(node, newnode, parent) + newnode.elts = [self.visit(child, newnode) for child in node.elts] + return newnode + + def visit_listcomp(self, node, parent): + """visit a ListComp node by returning a fresh instance of it""" + newnode = new.ListComp() + _lineno_parent(node, newnode, parent) + newnode.elt = self.visit(node.elt, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + return newnode + + def visit_name(self, node, parent): + """visit a Name node by returning a fresh instance of it""" + # True and False can be assigned to something in py2x, so we have to + # check first the asscontext + if self.asscontext == "Del": + newnode = new.DelName() + elif self.asscontext is not None: # Ass + assert self.asscontext == "Ass" + newnode = new.AssName() + elif node.id in CONST_NAME_TRANSFORMS: + newnode = new.Const(CONST_NAME_TRANSFORMS[node.id]) + _set_infos(node, newnode, parent) + return newnode + else: + newnode = new.Name() + _lineno_parent(node, newnode, parent) + newnode.name = node.id + # XXX REMOVE me : + if self.asscontext in ('Del', 'Ass'): # 'Aug' ?? + self._save_assignment(newnode) + return newnode + + def visit_bytes(self, node, parent): + """visit a Bytes node by returning a fresh instance of Const""" + newnode = new.Const(node.s) + _set_infos(node, newnode, parent) + return newnode + + def visit_num(self, node, parent): + """visit a Num node by returning a fresh instance of Const""" + newnode = new.Const(node.n) + _set_infos(node, newnode, parent) + return newnode + + def visit_pass(self, node, parent): + """visit a Pass node by returning a fresh instance of it""" + newnode = new.Pass() + _set_infos(node, newnode, parent) + return newnode + + def visit_str(self, node, parent): + """visit a Str node by returning a fresh instance of Const""" + newnode = new.Const(node.s) + _set_infos(node, newnode, parent) + return newnode + + def visit_print(self, node, parent): + """visit a Print node by returning a fresh instance of it""" + newnode = new.Print() + _lineno_parent(node, newnode, parent) + newnode.nl = node.nl + if node.dest is not None: + newnode.dest = self.visit(node.dest, newnode) + newnode.values = [self.visit(child, newnode) for child in node.values] + return newnode + + def visit_raise(self, node, parent): + """visit a Raise node by returning a fresh instance of it""" + newnode = new.Raise() + _lineno_parent(node, newnode, parent) + if node.type is not None: + newnode.exc = self.visit(node.type, newnode) + if node.inst is not None: + newnode.inst = self.visit(node.inst, newnode) + if node.tback is not None: + newnode.tback = self.visit(node.tback, newnode) + return newnode + + def visit_return(self, node, parent): + """visit a Return node by returning a fresh instance of it""" + newnode = new.Return() + _lineno_parent(node, newnode, parent) + if node.value is not None: + newnode.value = self.visit(node.value, newnode) + return newnode + + def visit_set(self, node, parent): + """visit a Set node by returning a fresh instance of it""" + newnode = new.Set() + _lineno_parent(node, newnode, parent) + newnode.elts = [self.visit(child, newnode) for child in node.elts] + return newnode + + def visit_setcomp(self, node, parent): + """visit a SetComp node by returning a fresh instance of it""" + newnode = new.SetComp() + _lineno_parent(node, newnode, parent) + newnode.elt = self.visit(node.elt, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + return newnode + + def visit_slice(self, node, parent): + """visit a Slice node by returning a fresh instance of it""" + newnode = new.Slice() + newnode.parent = parent + if node.lower is not None: + newnode.lower = self.visit(node.lower, newnode) + if node.upper is not None: + newnode.upper = self.visit(node.upper, newnode) + if node.step is not None: + newnode.step = self.visit(node.step, newnode) + return newnode + + def visit_subscript(self, node, parent): + """visit a Subscript node by returning a fresh instance of it""" + newnode = new.Subscript() + _lineno_parent(node, newnode, parent) + subcontext, self.asscontext = self.asscontext, None + newnode.value = self.visit(node.value, newnode) + newnode.slice = self.visit(node.slice, newnode) + self.asscontext = subcontext + return newnode + + def visit_tryexcept(self, node, parent): + """visit a TryExcept node by returning a fresh instance of it""" + newnode = new.TryExcept() + _lineno_parent(node, newnode, parent) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.handlers = [self.visit(child, newnode) for child in node.handlers] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + return newnode + + def visit_tryfinally(self, node, parent): + """visit a TryFinally node by returning a fresh instance of it""" + newnode = new.TryFinally() + _lineno_parent(node, newnode, parent) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.finalbody = [self.visit(n, newnode) for n in node.finalbody] + return newnode + + def visit_tuple(self, node, parent): + """visit a Tuple node by returning a fresh instance of it""" + newnode = new.Tuple() + _lineno_parent(node, newnode, parent) + newnode.elts = [self.visit(child, newnode) for child in node.elts] + return newnode + + def visit_unaryop(self, node, parent): + """visit a UnaryOp node by returning a fresh instance of it""" + newnode = new.UnaryOp() + _lineno_parent(node, newnode, parent) + newnode.operand = self.visit(node.operand, newnode) + newnode.op = _UNARY_OP_CLASSES[node.op.__class__] + return newnode + + def visit_while(self, node, parent): + """visit a While node by returning a fresh instance of it""" + newnode = new.While() + _lineno_parent(node, newnode, parent) + newnode.test = self.visit(node.test, newnode) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + return newnode + + def visit_with(self, node, parent): + newnode = new.With() + _lineno_parent(node, newnode, parent) + expr = self.visit(node.context_expr, newnode) + self.asscontext = "Ass" + if node.optional_vars is not None: + vars = self.visit(node.optional_vars, newnode) + else: + vars = None + self.asscontext = None + newnode.items = [(expr, vars)] + newnode.body = [self.visit(child, newnode) for child in node.body] + return newnode + + def visit_yield(self, node, parent): + """visit a Yield node by returning a fresh instance of it""" + return _create_yield_node(node, parent, self, new.Yield) + +class TreeRebuilder3k(TreeRebuilder): + """extend and overwrite TreeRebuilder for python3k""" + + def visit_arg(self, node, parent): + """visit a arg node by returning a fresh AssName instance""" + # the node is coming from py>=3.0, but we use AssName in py2.x + # XXX or we should instead introduce a Arg node in astroid ? + return self.visit_assname(node, parent, node.arg) + + def visit_nameconstant(self, node, parent): + # in Python 3.4 we have NameConstant for True / False / None + newnode = new.Const(node.value) + _set_infos(node, newnode, parent) + return newnode + + 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] + newnode.annotations = [ + self.visit(arg.annotation, newnode) if arg.annotation else None + for arg in node.args] + return newnode + + def visit_excepthandler(self, node, parent): + """visit an ExceptHandler node by returning a fresh instance of it""" + newnode = new.ExceptHandler() + _lineno_parent(node, newnode, parent) + if node.type is not None: + newnode.type = self.visit(node.type, newnode) + if node.name is not None: + newnode.name = self.visit_assname(node, newnode, node.name) + newnode.body = [self.visit(child, newnode) for child in node.body] + return newnode + + def visit_nonlocal(self, node, parent): + """visit a Nonlocal node and return a new instance of it""" + newnode = new.Nonlocal(node.names) + _set_infos(node, newnode, parent) + return newnode + + def visit_raise(self, node, parent): + """visit a Raise node by returning a fresh instance of it""" + newnode = new.Raise() + _lineno_parent(node, newnode, parent) + # no traceback; anyway it is not used in Pylint + if node.exc is not None: + newnode.exc = self.visit(node.exc, newnode) + if node.cause is not None: + newnode.cause = self.visit(node.cause, newnode) + return newnode + + def visit_starred(self, node, parent): + """visit a Starred node and return a new instance of it""" + newnode = new.Starred() + _lineno_parent(node, newnode, parent) + newnode.value = self.visit(node.value, newnode) + return newnode + + def visit_try(self, node, parent): + # python 3.3 introduce a new Try node replacing TryFinally/TryExcept nodes + if node.finalbody: + newnode = new.TryFinally() + _lineno_parent(node, newnode, parent) + newnode.finalbody = [self.visit(n, newnode) for n in node.finalbody] + if node.handlers: + excnode = new.TryExcept() + _lineno_parent(node, excnode, newnode) + excnode.body = [self.visit(child, excnode) for child in node.body] + excnode.handlers = [self.visit(child, excnode) for child in node.handlers] + excnode.orelse = [self.visit(child, excnode) for child in node.orelse] + newnode.body = [excnode] + else: + newnode.body = [self.visit(child, newnode) for child in node.body] + elif node.handlers: + newnode = new.TryExcept() + _lineno_parent(node, newnode, parent) + newnode.body = [self.visit(child, newnode) for child in node.body] + newnode.handlers = [self.visit(child, newnode) for child in node.handlers] + newnode.orelse = [self.visit(child, newnode) for child in node.orelse] + return newnode + + def visit_with(self, node, parent): + if 'items' not in node._fields: + # python < 3.3 + return super(TreeRebuilder3k, self).visit_with(node, parent) + + newnode = new.With() + _lineno_parent(node, newnode, parent) + def visit_child(child): + expr = self.visit(child.context_expr, newnode) + self.asscontext = 'Ass' + if child.optional_vars: + var = self.visit(child.optional_vars, newnode) + else: + var = None + self.asscontext = None + return expr, var + newnode.items = [visit_child(child) + for child in node.items] + newnode.body = [self.visit(child, newnode) for child in node.body] + return newnode + + def visit_yieldfrom(self, node, parent): + return _create_yield_node(node, parent, self, new.YieldFrom) + + def visit_class(self, node, parent): + newnode = super(TreeRebuilder3k, self).visit_class(node, parent) + newnode._newstyle = True + for keyword in node.keywords: + if keyword.arg == 'metaclass': + newnode._metaclass = self.visit(keyword, newnode).value + break + return newnode + +if sys.version_info >= (3, 0): + TreeRebuilder = TreeRebuilder3k + + diff -Nru astroid-1.0.1/astroid/scoped_nodes.py astroid-1.3.8/astroid/scoped_nodes.py --- astroid-1.0.1/astroid/scoped_nodes.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/scoped_nodes.py 2015-08-02 19:35:55.000000000 +0000 @@ -0,0 +1,1484 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""This module contains the classes for "scoped" node, i.e. which are opening a +new local scope in the language definition : Module, Class, Function (and +Lambda, GenExpr, DictComp and SetComp to some extent). +""" +from __future__ import with_statement + +__doctype__ = "restructuredtext en" + +import sys +import warnings +from itertools import chain +try: + from io import BytesIO +except ImportError: + from cStringIO import StringIO as BytesIO + +import six +from logilab.common.compat import builtins +from logilab.common.decorators import cached, cachedproperty + +from astroid.exceptions import NotFoundError, \ + AstroidBuildingException, InferenceError, ResolveError +from astroid.node_classes import Const, DelName, DelAttr, \ + Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \ + LookupMixIn, const_factory as cf, unpack_infer, CallFunc +from astroid.bases import NodeNG, InferenceContext, Instance, copy_context, \ + YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, \ + BUILTINS +from astroid.mixins import FilterStmtsMixin +from astroid.bases import Statement +from astroid.manager import AstroidManager + +ITER_METHODS = ('__iter__', '__getitem__') +PY3K = sys.version_info >= (3, 0) + +def _c3_merge(sequences): + """Merges MROs in *sequences* to a single MRO using the C3 algorithm. + + Adapted from http://www.python.org/download/releases/2.3/mro/. + + """ + result = [] + while True: + sequences = [s for s in sequences if s] # purge empty sequences + if not sequences: + return result + for s1 in sequences: # find merge candidates among seq heads + candidate = s1[0] + for s2 in sequences: + if candidate in s2[1:]: + candidate = None + break # reject the current head, it appears later + else: + break + if not candidate: + # Show all the remaining bases, which were considered as + # candidates for the next mro sequence. + bases = ["({})".format(", ".join(base.name + for base in subsequence)) + for subsequence in sequences] + raise ResolveError("Cannot create a consistent method resolution " + "order for bases %s" % ", ".join(bases)) + result.append(candidate) + # remove the chosen candidate + for seq in sequences: + if seq[0] == candidate: + del seq[0] + + +def _verify_duplicates_mro(sequences): + for sequence in sequences: + names = [node.qname() for node in sequence] + if len(names) != len(set(names)): + raise ResolveError('Duplicates found in the mro.') + + +def remove_nodes(func, cls): + def wrapper(*args, **kwargs): + nodes = [n for n in func(*args, **kwargs) if not isinstance(n, cls)] + if not nodes: + raise NotFoundError() + return nodes + return wrapper + + +def function_to_method(n, klass): + if isinstance(n, Function): + if n.type == 'classmethod': + return BoundMethod(n, klass) + if n.type != 'staticmethod': + return UnboundMethod(n) + return n + +def std_special_attributes(self, name, add_locals=True): + if add_locals: + locals = self.locals + else: + locals = {} + if name == '__name__': + return [cf(self.name)] + locals.get(name, []) + if name == '__doc__': + return [cf(self.doc)] + locals.get(name, []) + if name == '__dict__': + return [Dict()] + locals.get(name, []) + raise NotFoundError(name) + +MANAGER = AstroidManager() +def builtin_lookup(name): + """lookup a name into the builtin module + return the list of matching statements and the astroid for the builtin + module + """ + builtin_astroid = MANAGER.ast_from_module(builtins) + if name == '__dict__': + return builtin_astroid, () + try: + stmts = builtin_astroid.locals[name] + except KeyError: + stmts = () + return builtin_astroid, stmts + + +# TODO move this Mixin to mixins.py; problem: 'Function' in _scope_lookup +class LocalsDictNodeNG(LookupMixIn, NodeNG): + """ this class provides locals handling common to Module, Function + and Class nodes, including a dict like interface for direct access + to locals information + """ + + # attributes below are set by the builder module or by raw factories + + # dictionary of locals with name as key and node defining the local as + # value + + def qname(self): + """return the 'qualified' name of the node, eg module.name, + module.class.name ... + """ + if self.parent is None: + return self.name + return '%s.%s' % (self.parent.frame().qname(), self.name) + + def frame(self): + """return the first parent frame node (i.e. Module, Function or Class) + """ + return self + + def scope(self): + """return the first node defining a new scope (i.e. Module, + Function, Class, Lambda but also GenExpr, DictComp and SetComp) + """ + return self + + + def _scope_lookup(self, node, name, offset=0): + """XXX method for interfacing the scope lookup""" + try: + stmts = node._filter_stmts(self.locals[name], self, offset) + except KeyError: + stmts = () + if stmts: + return self, stmts + if self.parent: # i.e. not Module + # nested scope: if parent scope is a function, that's fine + # else jump to the module + pscope = self.parent.scope() + if not pscope.is_function: + pscope = pscope.root() + return pscope.scope_lookup(node, name) + return builtin_lookup(name) # Module + + + + def set_local(self, name, stmt): + """define in locals ( is the node defining the name) + if the node is a Module node (i.e. has globals), add the name to + globals + + if the name is already defined, ignore it + """ + #assert not stmt in self.locals.get(name, ()), (self, stmt) + self.locals.setdefault(name, []).append(stmt) + + __setitem__ = set_local + + def _append_node(self, child): + """append a child, linking it in the tree""" + self.body.append(child) + child.parent = self + + def add_local_node(self, child_node, name=None): + """append a child which should alter locals to the given node""" + if name != '__class__': + # add __class__ node as a child will cause infinite recursion later! + self._append_node(child_node) + self.set_local(name or child_node.name, child_node) + + + def __getitem__(self, item): + """method from the `dict` interface returning the first node + associated with the given name in the locals dictionary + + :type item: str + :param item: the name of the locally defined object + :raises KeyError: if the name is not defined + """ + return self.locals[item][0] + + def __iter__(self): + """method from the `dict` interface returning an iterator on + `self.keys()` + """ + return iter(self.keys()) + + def keys(self): + """method from the `dict` interface returning a tuple containing + locally defined names + """ + return list(self.locals.keys()) + + def values(self): + """method from the `dict` interface returning a tuple containing + locally defined nodes which are instance of `Function` or `Class` + """ + return [self[key] for key in self.keys()] + + def items(self): + """method from the `dict` interface returning a list of tuple + containing each locally defined name with its associated node, + which is an instance of `Function` or `Class` + """ + return list(zip(self.keys(), self.values())) + + + def __contains__(self, name): + return name in self.locals + has_key = __contains__ + +# Module ##################################################################### + +class Module(LocalsDictNodeNG): + _astroid_fields = ('body',) + + fromlineno = 0 + lineno = 0 + + # attributes below are set by the builder module or by raw factories + + # the file from which as been extracted the astroid representation. It may + # be None if the representation has been built from a built-in module + file = None + # Alternatively, if built from a string/bytes, this can be set + file_bytes = None + # encoding of python source file, so we can get unicode out of it (python2 + # only) + file_encoding = None + # the module name + name = None + # boolean for astroid built from source (i.e. ast) + pure_python = None + # boolean for package module + package = None + # dictionary of globals with name as key and node defining the global + # as value + globals = None + + # Future imports + future_imports = None + + # names of python special attributes (handled by getattr impl.) + special_attributes = set(('__name__', '__doc__', '__file__', '__path__', + '__dict__')) + # names of module attributes available through the global scope + scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) + + def __init__(self, name, doc, pure_python=True): + self.name = name + self.doc = doc + self.pure_python = pure_python + self.locals = self.globals = {} + self.body = [] + self.future_imports = set() + + def _get_stream(self): + if self.file_bytes is not None: + return BytesIO(self.file_bytes) + if self.file is not None: + stream = open(self.file, 'rb') + return stream + return None + + @property + def file_stream(self): + warnings.warn("file_stream property is deprecated and " + "it is slated for removal in astroid 1.6." + "Use the new method 'stream' instead.", + PendingDeprecationWarning, + stacklevel=2) + return self._get_stream() + + def stream(self): + """Get a stream to the underlying file or bytes.""" + return self._get_stream() + + def close(self): + """Close the underlying file streams.""" + warnings.warn("close method is deprecated and it is " + "slated for removal in astroid 1.6, along " + "with 'file_stream' property. " + "Its behaviour is replaced by managing each " + "file stream returned by the 'stream' method.", + PendingDeprecationWarning, + stacklevel=2) + + def block_range(self, lineno): + """return block line numbers. + + start from the beginning whatever the given lineno + """ + return self.fromlineno, self.tolineno + + def scope_lookup(self, node, name, offset=0): + if name in self.scope_attrs and not name in self.locals: + try: + return self, self.getattr(name) + except NotFoundError: + return self, () + return self._scope_lookup(node, name, offset) + + def pytype(self): + return '%s.module' % BUILTINS + + def display_type(self): + return 'Module' + + def getattr(self, name, context=None, ignore_locals=False): + if name in self.special_attributes: + if name == '__file__': + return [cf(self.file)] + self.locals.get(name, []) + if name == '__path__' and self.package: + return [List()] + self.locals.get(name, []) + return std_special_attributes(self, name) + if not ignore_locals and name in self.locals: + return self.locals[name] + if self.package: + try: + return [self.import_module(name, relative_only=True)] + except AstroidBuildingException: + raise NotFoundError(name) + except SyntaxError: + raise NotFoundError(name) + except Exception:# XXX pylint tests never pass here; do we need it? + import traceback + traceback.print_exc() + raise NotFoundError(name) + getattr = remove_nodes(getattr, DelName) + + def igetattr(self, name, context=None): + """inferred getattr""" + # set lookup name since this is necessary to infer on import nodes for + # instance + context = copy_context(context) + context.lookupname = name + try: + return _infer_stmts(self.getattr(name, context), context, frame=self) + except NotFoundError: + raise InferenceError(name) + + def fully_defined(self): + """return True if this module has been built from a .py file + and so contains a complete representation including the code + """ + return self.file is not None and self.file.endswith('.py') + + def statement(self): + """return the first parent node marked as statement node + consider a module as a statement... + """ + return self + + def previous_sibling(self): + """module has no sibling""" + return + + def next_sibling(self): + """module has no sibling""" + return + + if sys.version_info < (2, 8): + @cachedproperty + def _absolute_import_activated(self): + for stmt in self.locals.get('absolute_import', ()): + if isinstance(stmt, From) and stmt.modname == '__future__': + return True + return False + else: + _absolute_import_activated = True + + def absolute_import_activated(self): + return self._absolute_import_activated + + def import_module(self, modname, relative_only=False, level=None): + """import the given module considering self as context""" + if relative_only and level is None: + level = 0 + absmodname = self.relative_to_absolute_name(modname, level) + try: + return MANAGER.ast_from_module_name(absmodname) + except AstroidBuildingException: + # we only want to import a sub module or package of this module, + # skip here + if relative_only: + raise + return MANAGER.ast_from_module_name(modname) + + def relative_to_absolute_name(self, modname, level): + """return the absolute module name for a relative import. + + The relative import can be implicit or explicit. + """ + # XXX this returns non sens when called on an absolute import + # like 'pylint.checkers.astroid.utils' + # XXX doesn't return absolute name if self.name isn't absolute name + if self.absolute_import_activated() and level is None: + return modname + if level: + if self.package: + level = level - 1 + package_name = self.name.rsplit('.', level)[0] + elif self.package: + package_name = self.name + else: + package_name = self.name.rsplit('.', 1)[0] + if package_name: + if not modname: + return package_name + return '%s.%s' % (package_name, modname) + return modname + + + def wildcard_import_names(self): + """return the list of imported names when this module is 'wildcard + imported' + + It doesn't include the '__builtins__' name which is added by the + current CPython implementation of wildcard imports. + """ + # take advantage of a living module if it exists + try: + living = sys.modules[self.name] + except KeyError: + pass + else: + try: + return living.__all__ + except AttributeError: + return [name for name in living.__dict__.keys() + if not name.startswith('_')] + # else lookup the astroid + # + # We separate the different steps of lookup in try/excepts + # to avoid catching too many Exceptions + default = [name for name in self.keys() if not name.startswith('_')] + try: + all = self['__all__'] + except KeyError: + return default + try: + explicit = next(all.assigned_stmts()) + except InferenceError: + return default + except AttributeError: + # not an assignment node + # XXX infer? + return default + + # Try our best to detect the exported name. + infered = [] + try: + explicit = next(explicit.infer()) + except InferenceError: + return default + if not isinstance(explicit, (Tuple, List)): + return default + + str_const = lambda node: (isinstance(node, Const) and + isinstance(node.value, six.string_types)) + for node in explicit.elts: + if str_const(node): + infered.append(node.value) + else: + try: + infered_node = next(node.infer()) + except InferenceError: + continue + if str_const(infered_node): + infered.append(infered_node.value) + return infered + + + +class ComprehensionScope(LocalsDictNodeNG): + def frame(self): + return self.parent.frame() + + scope_lookup = LocalsDictNodeNG._scope_lookup + + +class GenExpr(ComprehensionScope): + _astroid_fields = ('elt', 'generators') + + def __init__(self): + self.locals = {} + self.elt = None + self.generators = [] + + +class DictComp(ComprehensionScope): + _astroid_fields = ('key', 'value', 'generators') + + def __init__(self): + self.locals = {} + self.key = None + self.value = None + self.generators = [] + + +class SetComp(ComprehensionScope): + _astroid_fields = ('elt', 'generators') + + def __init__(self): + self.locals = {} + self.elt = None + self.generators = [] + + +class _ListComp(NodeNG): + """class representing a ListComp node""" + _astroid_fields = ('elt', 'generators') + elt = None + generators = None + +if sys.version_info >= (3, 0): + class ListComp(_ListComp, ComprehensionScope): + """class representing a ListComp node""" + def __init__(self): + self.locals = {} +else: + class ListComp(_ListComp): + """class representing a ListComp node""" + +# Function ################################################################### + +def _infer_decorator_callchain(node): + """Detect decorator call chaining and see if the end result is a + static or a classmethod. + """ + if not isinstance(node, Function): + return + if not node.parent: + return + try: + # TODO: We don't handle multiple inference results right now, + # because there's no flow to reason when the return + # is what we are looking for, a static or a class method. + result = next(node.infer_call_result(node.parent)) + except (StopIteration, InferenceError): + return + if isinstance(result, Instance): + result = result._proxied + if isinstance(result, Class): + if result.is_subtype_of('%s.classmethod' % BUILTINS): + return 'classmethod' + if result.is_subtype_of('%s.staticmethod' % BUILTINS): + return 'staticmethod' + + +def _function_type(self): + """ + Function type, possible values are: + method, function, staticmethod, classmethod. + """ + # Can't infer that this node is decorated + # with a subclass of `classmethod` where `type` is first set, + # so do it here. + if self.decorators: + for node in self.decorators.nodes: + if isinstance(node, CallFunc): + # Handle the following case: + # @some_decorator(arg1, arg2) + # def func(...) + # + try: + current = next(node.func.infer()) + except InferenceError: + continue + _type = _infer_decorator_callchain(current) + if _type is not None: + return _type + + try: + for infered in node.infer(): + # Check to see if this returns a static or a class method. + _type = _infer_decorator_callchain(infered) + if _type is not None: + return _type + + if not isinstance(infered, Class): + continue + for ancestor in infered.ancestors(): + if not isinstance(ancestor, Class): + continue + if ancestor.is_subtype_of('%s.classmethod' % BUILTINS): + return 'classmethod' + elif ancestor.is_subtype_of('%s.staticmethod' % BUILTINS): + return 'staticmethod' + except InferenceError: + pass + return self._type + + +class Lambda(LocalsDictNodeNG, FilterStmtsMixin): + _astroid_fields = ('args', 'body',) + name = '' + + # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod' + type = 'function' + + def __init__(self): + self.locals = {} + self.args = [] + self.body = [] + + def pytype(self): + if 'method' in self.type: + return '%s.instancemethod' % BUILTINS + return '%s.function' % BUILTINS + + def display_type(self): + if 'method' in self.type: + return 'Method' + return 'Function' + + def callable(self): + return True + + 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) + else: + names = [] + if self.args.vararg: + names.append(self.args.vararg) + if self.args.kwarg: + names.append(self.args.kwarg) + return names + + def infer_call_result(self, caller, context=None): + """infer what a function is returning when called""" + return self.body.infer(context) + + def scope_lookup(self, node, name, offset=0): + 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 + offset = -1 + else: + # check this is not used in function decorators + frame = self + return frame._scope_lookup(node, name, offset) + + +class Function(Statement, Lambda): + if PY3K: + _astroid_fields = ('decorators', 'args', 'body', 'returns') + returns = None + else: + _astroid_fields = ('decorators', 'args', 'body') + + special_attributes = set(('__name__', '__doc__', '__dict__')) + is_function = True + # attributes below are set by the builder module or by raw factories + blockstart_tolineno = None + decorators = None + _type = "function" + type = cachedproperty(_function_type) + + def __init__(self, name, doc): + self.locals = {} + self.args = [] + self.body = [] + self.name = name + self.doc = doc + self.extra_decorators = [] + self.instance_attrs = {} + + @cachedproperty + def fromlineno(self): + # lineno is the line number of the first decorator, we want the def + # statement lineno + lineno = self.lineno + if self.decorators is not None: + lineno += sum(node.tolineno - node.lineno + 1 + for node in self.decorators.nodes) + + return lineno + + @cachedproperty + def blockstart_tolineno(self): + return self.args.tolineno + + def block_range(self, lineno): + """return block line numbers. + + start from the "def" position whatever the given lineno + """ + return self.fromlineno, self.tolineno + + def getattr(self, name, context=None): + """this method doesn't look in the instance_attrs dictionary since it's + done by an Instance proxy at inference time. + """ + if name == '__module__': + return [cf(self.root().qname())] + if name in self.instance_attrs: + return self.instance_attrs[name] + return std_special_attributes(self, name, False) + + def is_method(self): + """return true if the function node should be considered as a method""" + # check we are defined in a Class, because this is usually expected + # (e.g. pylint...) when is_method() return True + return self.type != 'function' and isinstance(self.parent.frame(), Class) + + def decoratornames(self): + """return a list of decorator qualified names""" + result = set() + decoratornodes = [] + if self.decorators is not None: + decoratornodes += self.decorators.nodes + decoratornodes += self.extra_decorators + for decnode in decoratornodes: + for infnode in decnode.infer(): + result.add(infnode.qname()) + return result + decoratornames = cached(decoratornames) + + def is_bound(self): + """return true if the function is bound to an Instance or a class""" + return self.type == 'classmethod' + + def is_abstract(self, pass_is_abstract=True): + """Returns True if the method is abstract. + + A method is considered abstract if + - the only statement is 'raise NotImplementedError', or + - the only statement is 'pass' and pass_is_abstract is True, or + - the method is annotated with abc.astractproperty/abc.abstractmethod + """ + if self.decorators: + for node in self.decorators.nodes: + try: + infered = next(node.infer()) + except InferenceError: + continue + if infered and infered.qname() in ('abc.abstractproperty', + 'abc.abstractmethod'): + return True + + for child_node in self.body: + if isinstance(child_node, Raise): + if child_node.raises_not_implemented(): + return True + if pass_is_abstract and isinstance(child_node, Pass): + return True + return False + # empty function is the same as function with a single "pass" statement + if pass_is_abstract: + return True + + def is_generator(self): + """return true if this is a generator function""" + # XXX should be flagged, not computed + return next(self.nodes_of_class((Yield, YieldFrom), + skip_klass=(Function, Lambda)), False) + + def infer_call_result(self, caller, context=None): + """infer what a function is returning when called""" + if self.is_generator(): + yield Generator() + return + # This is really a gigantic hack to work around metaclass generators + # that return transient class-generating functions. Pylint's AST structure + # cannot handle a base class object that is only used for calling __new__, + # but does not contribute to the inheritance structure itself. We inject + # a fake class into the hierarchy here for several well-known metaclass + # generators, and filter it out later. + if (self.name == 'with_metaclass' and + len(self.args.args) == 1 and + self.args.vararg is not None): + metaclass = next(caller.args[0].infer(context)) + if isinstance(metaclass, Class): + c = Class('temporary_class', None) + c.hide = True + c.parent = self + bases = [next(b.infer(context)) for b in caller.args[1:]] + c.bases = [base for base in bases if base != YES] + c._metaclass = metaclass + yield c + return + returns = self.nodes_of_class(Return, skip_klass=Function) + for returnnode in returns: + if returnnode.value is None: + yield Const(None) + else: + try: + for infered in returnnode.value.infer(context): + yield infered + except InferenceError: + yield YES + + +def _rec_get_names(args, names=None): + """return a list of all argument names""" + if names is None: + names = [] + for arg in args: + if isinstance(arg, Tuple): + _rec_get_names(arg.elts, names) + else: + names.append(arg.name) + return names + + +# Class ###################################################################### + + +def _is_metaclass(klass, seen=None): + """ Return if the given class can be + used as a metaclass. + """ + if klass.name == 'type': + return True + if seen is None: + seen = set() + for base in klass.bases: + try: + for baseobj in base.infer(): + if baseobj in seen: + continue + else: + seen.add(baseobj) + if isinstance(baseobj, Instance): + # not abstract + return False + if baseobj is YES: + continue + if baseobj is klass: + continue + if not isinstance(baseobj, Class): + continue + if baseobj._type == 'metaclass': + return True + if _is_metaclass(baseobj, seen): + return True + except InferenceError: + continue + return False + + +def _class_type(klass, ancestors=None): + """return a Class node type to differ metaclass, interface and exception + from 'regular' classes + """ + # XXX we have to store ancestors in case we have a ancestor loop + if klass._type is not None: + return klass._type + if _is_metaclass(klass): + klass._type = 'metaclass' + elif klass.name.endswith('Interface'): + klass._type = 'interface' + elif klass.name.endswith('Exception'): + klass._type = 'exception' + else: + if ancestors is None: + ancestors = set() + if klass in ancestors: + # XXX we are in loop ancestors, and have found no type + klass._type = 'class' + return 'class' + ancestors.add(klass) + for base in klass.ancestors(recurs=False): + name = _class_type(base, ancestors) + if name != 'class': + if name == 'metaclass' and not _is_metaclass(klass): + # don't propagate it if the current class + # can't be a metaclass + continue + klass._type = base.type + break + if klass._type is None: + klass._type = 'class' + return klass._type + +def _iface_hdlr(iface_node): + """a handler function used by interfaces to handle suspicious + interface nodes + """ + return True + + +class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin): + + # some of the attributes below are set by the builder module or + # by a raw factories + + # a dictionary of class instances attributes + _astroid_fields = ('decorators', 'bases', 'body') # name + + decorators = None + special_attributes = set(('__name__', '__doc__', '__dict__', '__module__', + '__bases__', '__mro__', '__subclasses__')) + blockstart_tolineno = None + + _type = None + _metaclass_hack = False + hide = False + type = property(_class_type, + doc="class'type, possible values are 'class' | " + "'metaclass' | 'interface' | 'exception'") + + def __init__(self, name, doc): + self.instance_attrs = {} + self.locals = {} + self.bases = [] + self.body = [] + self.name = name + self.doc = doc + + def _newstyle_impl(self, context=None): + if context is None: + context = InferenceContext() + if self._newstyle is not None: + return self._newstyle + for base in self.ancestors(recurs=False, context=context): + if base._newstyle_impl(context): + self._newstyle = True + break + klass = self._explicit_metaclass() + # could be any callable, we'd need to infer the result of klass(name, + # bases, dict). punt if it's not a class node. + if klass is not None and isinstance(klass, Class): + self._newstyle = klass._newstyle_impl(context) + if self._newstyle is None: + self._newstyle = False + return self._newstyle + + _newstyle = None + newstyle = property(_newstyle_impl, + doc="boolean indicating if it's a new style class" + "or not") + + @cachedproperty + def blockstart_tolineno(self): + if self.bases: + return self.bases[-1].tolineno + else: + return self.fromlineno + + def block_range(self, lineno): + """return block line numbers. + + start from the "class" position whatever the given lineno + """ + return self.fromlineno, self.tolineno + + def pytype(self): + if self.newstyle: + return '%s.type' % BUILTINS + return '%s.classobj' % BUILTINS + + def display_type(self): + return 'Class' + + def callable(self): + return True + + def is_subtype_of(self, type_name, context=None): + if self.qname() == type_name: + return True + for anc in self.ancestors(context=context): + if anc.qname() == type_name: + return True + + def infer_call_result(self, caller, context=None): + """infer what a class is returning when called""" + if self.is_subtype_of('%s.type' % (BUILTINS,), context) and len(caller.args) == 3: + name_node = next(caller.args[0].infer(context)) + if (isinstance(name_node, Const) and + isinstance(name_node.value, six.string_types)): + name = name_node.value + else: + yield YES + return + result = Class(name, None) + bases = next(caller.args[1].infer(context)) + if isinstance(bases, (Tuple, List)): + result.bases = bases.itered() + else: + # There is currently no AST node that can represent an 'unknown' + # node (YES is not an AST node), therefore we simply return YES here + # although we know at least the name of the class. + yield YES + return + result.parent = caller.parent + yield result + else: + yield Instance(self) + + def scope_lookup(self, node, name, offset=0): + if any(node == base or base.parent_of(node) + for base in self.bases): + # Handle the case where we have either a name + # in the bases of a class, which exists before + # the actual definition or the case where we have + # a Getattr node, with that name. + # + # name = ... + # class A(name): + # def name(self): ... + # + # import name + # class A(name.Name): + # def name(self): ... + + frame = self.parent.frame() + # line offset to avoid that class A(A) resolve the ancestor to + # the defined class + offset = -1 + else: + frame = self + return frame._scope_lookup(node, name, offset) + + # list of parent class as a list of string (i.e. names as they appear + # in the class definition) XXX bw compat + def basenames(self): + return [bnode.as_string() for bnode in self.bases] + basenames = property(basenames) + + def ancestors(self, recurs=True, context=None): + """return an iterator on the node base classes in a prefixed + depth first order + + :param recurs: + boolean indicating if it should recurse or return direct + ancestors only + """ + # FIXME: should be possible to choose the resolution order + # FIXME: inference make infinite loops possible here + yielded = set([self]) + if context is None: + context = InferenceContext() + if sys.version_info[0] >= 3: + if not self.bases and self.qname() != 'builtins.object': + yield builtin_lookup("object")[1][0] + return + + for stmt in self.bases: + with context.restore_path(): + try: + for baseobj in stmt.infer(context): + if not isinstance(baseobj, Class): + if isinstance(baseobj, Instance): + baseobj = baseobj._proxied + else: + # duh ? + continue + if not baseobj.hide: + if baseobj in yielded: + continue # cf xxx above + yielded.add(baseobj) + yield baseobj + if recurs: + for grandpa in baseobj.ancestors(recurs=True, + context=context): + if grandpa is self: + # This class is the ancestor of itself. + break + if grandpa in yielded: + continue # cf xxx above + yielded.add(grandpa) + yield grandpa + except InferenceError: + # XXX log error ? + continue + + def local_attr_ancestors(self, name, context=None): + """return an iterator on astroid representation of parent classes + which have defined in their locals + """ + for astroid in self.ancestors(context=context): + if name in astroid: + yield astroid + + def instance_attr_ancestors(self, name, context=None): + """return an iterator on astroid representation of parent classes + which have defined in their instance attribute dictionary + """ + for astroid in self.ancestors(context=context): + if name in astroid.instance_attrs: + yield astroid + + def has_base(self, node): + return node in self.bases + + def local_attr(self, name, context=None): + """return the list of assign node associated to name in this class + locals or in its parents + + :raises `NotFoundError`: + if no attribute with this name has been find in this class or + its parent classes + """ + try: + return self.locals[name] + except KeyError: + # get if from the first parent implementing it if any + for class_node in self.local_attr_ancestors(name, context): + return class_node.locals[name] + raise NotFoundError(name) + local_attr = remove_nodes(local_attr, DelAttr) + + def instance_attr(self, name, context=None): + """return the astroid nodes associated to name in this class instance + attributes dictionary and in its parents + + :raises `NotFoundError`: + if no attribute with this name has been find in this class or + its parent classes + """ + # Return a copy, so we don't modify self.instance_attrs, + # which could lead to infinite loop. + values = list(self.instance_attrs.get(name, [])) + # get all values from parents + for class_node in self.instance_attr_ancestors(name, context): + values += class_node.instance_attrs[name] + if not values: + raise NotFoundError(name) + return values + instance_attr = remove_nodes(instance_attr, DelAttr) + + def instanciate_class(self): + """return Instance of Class node, else return self""" + return Instance(self) + + def getattr(self, name, context=None): + """this method doesn't look in the instance_attrs dictionary since it's + done by an Instance proxy at inference time. + + It may return a YES object if the attribute has not been actually + found but a __getattr__ or __getattribute__ method is defined + """ + values = self.locals.get(name, []) + if name in self.special_attributes: + if name == '__module__': + return [cf(self.root().qname())] + values + # FIXME: do we really need the actual list of ancestors? + # returning [Tuple()] + values don't break any test + # this is ticket http://www.logilab.org/ticket/52785 + # XXX need proper meta class handling + MRO implementation + if name == '__bases__' or (name == '__mro__' and self.newstyle): + node = Tuple() + node.items = self.ancestors(recurs=True, context=context) + return [node] + values + return std_special_attributes(self, name) + # don't modify the list in self.locals! + values = list(values) + for classnode in self.ancestors(recurs=True, context=context): + values += classnode.locals.get(name, []) + if not values: + raise NotFoundError(name) + return values + + def igetattr(self, name, context=None): + """inferred getattr, need special treatment in class to handle + descriptors + """ + # set lookup name since this is necessary to infer on import nodes for + # instance + context = copy_context(context) + context.lookupname = name + try: + for infered in _infer_stmts(self.getattr(name, context), context, + frame=self): + # yield YES object instead of descriptors when necessary + if not isinstance(infered, Const) and isinstance(infered, Instance): + try: + infered._proxied.getattr('__get__', context) + except NotFoundError: + yield infered + else: + yield YES + else: + yield function_to_method(infered, self) + except NotFoundError: + if not name.startswith('__') and self.has_dynamic_getattr(context): + # class handle some dynamic attributes, return a YES object + yield YES + else: + raise InferenceError(name) + + def has_dynamic_getattr(self, context=None): + """return True if the class has a custom __getattr__ or + __getattribute__ method + """ + # need to explicitly handle optparse.Values (setattr is not detected) + if self.name == 'Values' and self.root().name == 'optparse': + return True + try: + self.getattr('__getattr__', context) + return True + except NotFoundError: + #if self.newstyle: XXX cause an infinite recursion error + try: + getattribute = self.getattr('__getattribute__', context)[0] + if getattribute.root().name != BUILTINS: + # class has a custom __getattribute__ defined + return True + except NotFoundError: + pass + return False + + def methods(self): + """return an iterator on all methods defined in the class and + its ancestors + """ + done = {} + for astroid in chain(iter((self,)), self.ancestors()): + for meth in astroid.mymethods(): + if meth.name in done: + continue + done[meth.name] = None + yield meth + + def mymethods(self): + """return an iterator on all methods defined in the class""" + for member in self.values(): + if isinstance(member, Function): + yield member + + def interfaces(self, herited=True, handler_func=_iface_hdlr): + """return an iterator on interfaces implemented by the given + class node + """ + # FIXME: what if __implements__ = (MyIFace, MyParent.__implements__)... + try: + implements = Instance(self).getattr('__implements__')[0] + except NotFoundError: + return + if not herited and not implements.frame() is self: + return + found = set() + missing = False + for iface in unpack_infer(implements): + if iface is YES: + missing = True + continue + if not iface in found and handler_func(iface): + found.add(iface) + yield iface + if missing: + raise InferenceError() + + _metaclass = None + def _explicit_metaclass(self): + """ Return the explicit defined metaclass + for the current class. + + An explicit defined metaclass is defined + either by passing the ``metaclass`` keyword argument + in the class definition line (Python 3) or (Python 2) by + having a ``__metaclass__`` class attribute, or if there are + no explicit bases but there is a global ``__metaclass__`` variable. + """ + for base in self.bases: + try: + for baseobj in base.infer(): + if isinstance(baseobj, Class) and baseobj.hide: + self._metaclass = baseobj._metaclass + self._metaclass_hack = True + break + except InferenceError: + pass + + if self._metaclass: + # Expects this from Py3k TreeRebuilder + try: + return next(node for node in self._metaclass.infer() + if node is not YES) + except (InferenceError, StopIteration): + return None + if sys.version_info >= (3, ): + return None + + if '__metaclass__' in self.locals: + assignment = self.locals['__metaclass__'][-1] + elif self.bases: + return None + elif '__metaclass__' in self.root().locals: + assignments = [ass for ass in self.root().locals['__metaclass__'] + if ass.lineno < self.lineno] + if not assignments: + return None + assignment = assignments[-1] + else: + return None + + try: + infered = next(assignment.infer()) + except InferenceError: + return + if infered is YES: # don't expose this + return None + return infered + + def metaclass(self): + """ Return the metaclass of this class. + + If this class does not define explicitly a metaclass, + then the first defined metaclass in ancestors will be used + instead. + """ + klass = self._explicit_metaclass() + if klass is None: + for parent in self.ancestors(): + klass = parent.metaclass() + if klass is not None: + break + return klass + + def has_metaclass_hack(self): + return self._metaclass_hack + + def _islots(self): + """ Return an iterator with the inferred slots. """ + if '__slots__' not in self.locals: + return + for slots in self.igetattr('__slots__'): + # check if __slots__ is a valid type + for meth in ITER_METHODS: + try: + slots.getattr(meth) + break + except NotFoundError: + continue + else: + continue + + if isinstance(slots, Const): + # a string. Ignore the following checks, + # but yield the node, only if it has a value + if slots.value: + yield slots + continue + if not hasattr(slots, 'itered'): + # we can't obtain the values, maybe a .deque? + continue + + if isinstance(slots, Dict): + values = [item[0] for item in slots.items] + else: + values = slots.itered() + if values is YES: + continue + + for elt in values: + try: + for infered in elt.infer(): + if infered is YES: + continue + if (not isinstance(infered, Const) or + not isinstance(infered.value, + six.string_types)): + continue + if not infered.value: + continue + yield infered + except InferenceError: + continue + + # Cached, because inferring them all the time is expensive + @cached + def slots(self): + """Get all the slots for this node. + + If the class doesn't define any slot, through `__slots__` + variable, then this function will return a None. + Also, it will return None in the case the slots weren't inferred. + Otherwise, it will return a list of slot names. + """ + if not self.newstyle: + raise NotImplementedError( + "The concept of slots is undefined for old-style classes.") + + slots = self._islots() + try: + first = next(slots) + except StopIteration: + # The class doesn't have a __slots__ definition. + return None + return [first] + list(slots) + + def _inferred_bases(self, recurs=True, context=None): + # TODO(cpopa): really similar with .ancestors, + # but the difference is when one base is inferred, + # only the first object is wanted. That's because + # we aren't interested in superclasses, as in the following + # example: + # + # class SomeSuperClass(object): pass + # class SomeClass(SomeSuperClass): pass + # class Test(SomeClass): pass + # + # Inferring SomeClass from the Test's bases will give + # us both SomeClass and SomeSuperClass, but we are interested + # only in SomeClass. + + if context is None: + context = InferenceContext() + if sys.version_info[0] >= 3: + if not self.bases and self.qname() != 'builtins.object': + yield builtin_lookup("object")[1][0] + return + + for stmt in self.bases: + try: + baseobj = next(stmt.infer(context=context)) + except InferenceError: + # XXX log error ? + continue + if isinstance(baseobj, Instance): + baseobj = baseobj._proxied + if not isinstance(baseobj, Class): + continue + if not baseobj.hide: + yield baseobj + + def mro(self, context=None): + """Get the method resolution order, using C3 linearization. + + It returns the list of ancestors sorted by the mro. + This will raise `NotImplementedError` for old-style classes, since + they don't have the concept of MRO. + """ + if not self.newstyle: + raise NotImplementedError( + "Could not obtain mro for old-style classes.") + + bases = list(self._inferred_bases(context=context)) + unmerged_mro = ([[self]] + + [base.mro() for base in bases if base is not self] + + [bases]) + + _verify_duplicates_mro(unmerged_mro) + return _c3_merge(unmerged_mro) diff -Nru astroid-1.0.1/astroid/tests/resources.py astroid-1.3.8/astroid/tests/resources.py --- astroid-1.0.1/astroid/tests/resources.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/resources.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,72 @@ +# Copyright 2014 Google, Inc. All rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +import os +import sys + +import pkg_resources + +from astroid import builder +from astroid import MANAGER +from astroid.bases import BUILTINS + + +DATA_DIR = 'testdata/python{}/'.format(sys.version_info[0]) + +def find(name): + return pkg_resources.resource_filename( + 'astroid.tests', os.path.normpath(os.path.join(DATA_DIR, name))) + + +def build_file(path, modname=None): + return builder.AstroidBuilder().file_build(find(path), modname) + + +class SysPathSetup(object): + def setUp(self): + sys.path.insert(0, find('')) + + def tearDown(self): + del sys.path[0] + datadir = find('') + for key in list(sys.path_importer_cache): + if key.startswith(datadir): + del sys.path_importer_cache[key] + + +class AstroidCacheSetupMixin(object): + """Mixin for handling the astroid cache problems. + + When clearing the astroid cache, some tests fails due to + cache inconsistencies, where some objects had a different + builtins object referenced. + This saves the builtins module and makes sure to add it + back to the astroid_cache after the tests finishes. + The builtins module is special, since some of the + transforms for a couple of its objects (str, bytes etc) + are executed only once, so astroid_bootstrapping will be + useless for retrieving the original builtins module. + """ + + @classmethod + def setUpClass(cls): + cls._builtins = MANAGER.astroid_cache.get(BUILTINS) + + @classmethod + def tearDownClass(cls): + if cls._builtins: + MANAGER.astroid_cache[BUILTINS] = cls._builtins diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/absimp/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/absimp/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/absimp/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/absimp/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,5 @@ +"""a package with absolute import activated +""" + +from __future__ import absolute_import + diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/absimp/sidepackage/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/absimp/sidepackage/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/absimp/sidepackage/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/absimp/sidepackage/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +"""a side package with nothing in it +""" + diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/absimp/string.py astroid-1.3.8/astroid/tests/testdata/python2/data/absimp/string.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/absimp/string.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/absimp/string.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +from __future__ import absolute_import, print_function +import string +print(string) diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/absimport.py astroid-1.3.8/astroid/tests/testdata/python2/data/absimport.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/absimport.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/absimport.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +from __future__ import absolute_import +import email +from email import message diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/all.py astroid-1.3.8/astroid/tests/testdata/python2/data/all.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/all.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/all.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,9 @@ + +name = 'a' +_bla = 2 +other = 'o' +class Aaa: pass + +def func(): print 'yo' + +__all__ = 'Aaa', '_bla', 'name' diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/appl/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/appl/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/appl/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/appl/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +""" +Init +""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/appl/myConnection.py astroid-1.3.8/astroid/tests/testdata/python2/data/appl/myConnection.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/appl/myConnection.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/appl/myConnection.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,11 @@ +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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/clientmodule_test.py astroid-1.3.8/astroid/tests/testdata/python2/data/clientmodule_test.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/clientmodule_test.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/clientmodule_test.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,32 @@ +""" docstring for file clientmodule.py """ +from data.suppliermodule_test import Interface as IFace, DoNothing + +class Toto: pass + +class Ancestor: + """ Ancestor method """ + __implements__ = (IFace,) + + def __init__(self, value): + local_variable = 0 + self.attr = 'this method shouldn\'t have a docstring' + self.__value = value + + def get_value(self): + """ nice docstring ;-) """ + return self.__value + + def set_value(self, value): + self.__value = value + return 'this method shouldn\'t have a docstring' + +class Specialization(Ancestor): + TYPE = 'final class' + top = 'class' + + def __init__(self, value, _id): + Ancestor.__init__(self, value) + self._id = _id + self.relation = DoNothing() + self.toto = Toto() + diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/descriptor_crash.py astroid-1.3.8/astroid/tests/testdata/python2/data/descriptor_crash.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/descriptor_crash.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/descriptor_crash.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,11 @@ + +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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/email.py astroid-1.3.8/astroid/tests/testdata/python2/data/email.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/email.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/email.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +"""fake email module to test absolute import doesn't grab this one""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/format.py astroid-1.3.8/astroid/tests/testdata/python2/data/format.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/format.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/format.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,34 @@ +"""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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +__revision__="$Id: __init__.py,v 1.1 2005-06-13 20:55:20 syt Exp $" diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/joined_strings.py astroid-1.3.8/astroid/tests/testdata/python2/data/joined_strings.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/joined_strings.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/joined_strings.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,1051 @@ +x = ('R0lGODlhigJnAef/AAABAAEEAAkCAAMGAg0GBAYJBQoMCBMODQ4QDRITEBkS' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7') \ No newline at end of file diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/lmfp/foo.py astroid-1.3.8/astroid/tests/testdata/python2/data/lmfp/foo.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/lmfp/foo.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/lmfp/foo.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,6 @@ +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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/lmfp/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/lmfp/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/lmfp/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/lmfp/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,2 @@ +# force a "direct" python import +from . import foo diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/module1abs/core.py astroid-1.3.8/astroid/tests/testdata/python2/data/module1abs/core.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/module1abs/core.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/module1abs/core.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +import sys diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/module1abs/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/module1abs/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/module1abs/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/module1abs/__init__.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,4 @@ +from __future__ import absolute_import +from . import core +from .core import * +print sys.version diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/module2.py astroid-1.3.8/astroid/tests/testdata/python2/data/module2.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/module2.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/module2.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,143 @@ +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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/module.py astroid-1.3.8/astroid/tests/testdata/python2/data/module.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/module.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/module.py 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,89 @@ +"""test module for astroid +""" + +__revision__ = '$Id: module.py,v 1.2 2005-11-02 11:56:54 syt Exp $' +from logilab.common.shellutils import ProgressBar as pb +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: + print '!!!' + + +class YO: + """hehe""" + a = 1 + + def __init__(self): + try: + self.yo = 1 + except ValueError, 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""" + global MY_DICT + try: + MY_DICT = {} + local = None + autre = [a for (a, b) in MY_DICT if b] + if b in autre: + print 'yo', + else: + if a in autre: + print '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 in b + class_method = classmethod(class_method) + + +def four_args(a, b, c, d): + """four arguments (was nested_args)""" + print a, b, c, d + 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) + map(lambda x, y: (y, x), a) +redirect = four_args + Binary files /tmp/tehDuGV_EZ/astroid-1.0.1/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg and /tmp/WwBlO9ZnuM/astroid-1.3.8/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg differ Binary files /tmp/tehDuGV_EZ/astroid-1.0.1/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip and /tmp/WwBlO9ZnuM/astroid-1.3.8/astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip differ diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/noendingnewline.py astroid-1.3.8/astroid/tests/testdata/python2/data/noendingnewline.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/noendingnewline.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/noendingnewline.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,36 @@ +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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/nonregr.py astroid-1.3.8/astroid/tests/testdata/python2/data/nonregr.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/nonregr.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/nonregr.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,57 @@ +from __future__ import generators + +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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/notall.py astroid-1.3.8/astroid/tests/testdata/python2/data/notall.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/notall.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/notall.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,8 @@ + +name = 'a' +_bla = 2 +other = 'o' +class Aaa: pass + +def func(): print 'yo' + diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/package/absimport.py astroid-1.3.8/astroid/tests/testdata/python2/data/package/absimport.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/package/absimport.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/package/absimport.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,6 @@ +from __future__ import absolute_import, print_function +import import_package_subpackage_module # fail +print(import_package_subpackage_module) + +from . import hello as hola + diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/package/hello.py astroid-1.3.8/astroid/tests/testdata/python2/data/package/hello.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/package/hello.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/package/hello.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,2 @@ +"""hello module""" + diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/package/import_package_subpackage_module.py astroid-1.3.8/astroid/tests/testdata/python2/data/package/import_package_subpackage_module.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/package/import_package_subpackage_module.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/package/import_package_subpackage_module.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,49 @@ +# 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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/package/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/package/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/package/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/package/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,4 @@ +"""package's __init__ file""" + + +from . import subpackage diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/package/subpackage/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/package/subpackage/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/package/subpackage/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/package/subpackage/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +"""package.subpackage""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/package/subpackage/module.py astroid-1.3.8/astroid/tests/testdata/python2/data/package/subpackage/module.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/package/subpackage/module.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/package/subpackage/module.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +"""package.subpackage.module""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/recursion.py astroid-1.3.8/astroid/tests/testdata/python2/data/recursion.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/recursion.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/recursion.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +""" For issue #25 """ +class Base(object): + pass \ No newline at end of file diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/SSL1/Connection1.py astroid-1.3.8/astroid/tests/testdata/python2/data/SSL1/Connection1.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/SSL1/Connection1.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/SSL1/Connection1.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,14 @@ +"""M2Crypto.SSL.Connection + +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" + +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 -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/SSL1/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/SSL1/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/SSL1/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/SSL1/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +from Connection1 import Connection diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/suppliermodule_test.py astroid-1.3.8/astroid/tests/testdata/python2/data/suppliermodule_test.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/suppliermodule_test.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/suppliermodule_test.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,13 @@ +""" file suppliermodule.py """ + +class NotImplemented(Exception): + pass + +class Interface: + def get_value(self): + raise NotImplemented() + + def set_value(self, value): + raise NotImplemented() + +class DoNothing : pass diff -Nru astroid-1.0.1/astroid/tests/testdata/python2/data/unicode_package/__init__.py astroid-1.3.8/astroid/tests/testdata/python2/data/unicode_package/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python2/data/unicode_package/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python2/data/unicode_package/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +x = "șțîâ" \ No newline at end of file diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/absimp/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/absimp/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/absimp/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/absimp/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,5 @@ +"""a package with absolute import activated +""" + +from __future__ import absolute_import + diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +"""a side package with nothing in it +""" + diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/absimp/string.py astroid-1.3.8/astroid/tests/testdata/python3/data/absimp/string.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/absimp/string.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/absimp/string.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +from __future__ import absolute_import, print_function +import string +print(string) diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/absimport.py astroid-1.3.8/astroid/tests/testdata/python3/data/absimport.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/absimport.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/absimport.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ + +import email +from email import message diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/all.py astroid-1.3.8/astroid/tests/testdata/python3/data/all.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/all.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/all.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,9 @@ + +name = 'a' +_bla = 2 +other = 'o' +class Aaa: pass + +def func(): print('yo') + +__all__ = 'Aaa', '_bla', 'name' diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/appl/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/appl/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/appl/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/appl/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +""" +Init +""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/appl/myConnection.py astroid-1.3.8/astroid/tests/testdata/python3/data/appl/myConnection.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/appl/myConnection.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/appl/myConnection.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,11 @@ +from data import SSL1 +class MyConnection(SSL1.Connection): + + """An SSL connection.""" + + def __init__(self, dummy): + print('MyConnection init') + +if __name__ == '__main__': + myConnection = MyConnection(' ') + input('Press Enter to continue...') diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/clientmodule_test.py astroid-1.3.8/astroid/tests/testdata/python3/data/clientmodule_test.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/clientmodule_test.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/clientmodule_test.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,32 @@ +""" docstring for file clientmodule.py """ +from data.suppliermodule_test import Interface as IFace, DoNothing + +class Toto: pass + +class Ancestor: + """ Ancestor method """ + __implements__ = (IFace,) + + def __init__(self, value): + local_variable = 0 + self.attr = 'this method shouldn\'t have a docstring' + self.__value = value + + def get_value(self): + """ nice docstring ;-) """ + return self.__value + + def set_value(self, value): + self.__value = value + return 'this method shouldn\'t have a docstring' + +class Specialization(Ancestor): + TYPE = 'final class' + top = 'class' + + def __init__(self, value, _id): + Ancestor.__init__(self, value) + self._id = _id + self.relation = DoNothing() + self.toto = Toto() + diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/descriptor_crash.py astroid-1.3.8/astroid/tests/testdata/python3/data/descriptor_crash.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/descriptor_crash.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/descriptor_crash.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,11 @@ + +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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/email.py astroid-1.3.8/astroid/tests/testdata/python3/data/email.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/email.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/email.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +"""fake email module to test absolute import doesn't grab this one""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/format.py astroid-1.3.8/astroid/tests/testdata/python3/data/format.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/format.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/format.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,34 @@ +"""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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +__revision__="$Id: __init__.py,v 1.1 2005-06-13 20:55:20 syt Exp $" diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/joined_strings.py astroid-1.3.8/astroid/tests/testdata/python3/data/joined_strings.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/joined_strings.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/joined_strings.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,1051 @@ +x = ('R0lGODlhigJnAef/AAABAAEEAAkCAAMGAg0GBAYJBQoMCBMODQ4QDRITEBkS' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7' + +'CxsSEhkWDhYYFQ0aJhkaGBweGyccGh8hHiIkIiMmGTEiHhQoPSYoJSkqKDcp' + +'Ii0uLDAxLzI0Mh44U0gxMDI5JkM0JjU3NDY6Kjc5Njo7OUE8Ozw+Oz89QTxA' + +'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7') \ No newline at end of file diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/lmfp/foo.py astroid-1.3.8/astroid/tests/testdata/python3/data/lmfp/foo.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/lmfp/foo.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/lmfp/foo.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,6 @@ +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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/lmfp/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/lmfp/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/lmfp/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/lmfp/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,2 @@ +# force a "direct" python import +from . import foo diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/module1abs/core.py astroid-1.3.8/astroid/tests/testdata/python3/data/module1abs/core.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/module1abs/core.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/module1abs/core.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +import sys diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/module1abs/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/module1abs/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/module1abs/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/module1abs/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,4 @@ + +from . import core +from .core import * +print(sys.version) diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/module2.py astroid-1.3.8/astroid/tests/testdata/python3/data/module2.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/module2.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/module2.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,143 @@ +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 repr(1) +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') + 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('bonjour', file=stream) +print('salut', end=' ', file=stream) + +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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/module.py astroid-1.3.8/astroid/tests/testdata/python3/data/module.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/module.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/module.py 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,89 @@ +"""test module for astroid +""" + +__revision__ = '$Id: module.py,v 1.2 2005-11-02 11:56:54 syt Exp $' +from logilab.common.shellutils import ProgressBar as pb +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: + print('!!!') + + +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""" + global MY_DICT + try: + MY_DICT = {} + local = None + autre = [a for (a, b) in MY_DICT if b] + if b in autre: + print('yo', end=' ') + else: + if a in autre: + print('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)""" + print(a, b, c, d) + 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 + Binary files /tmp/tehDuGV_EZ/astroid-1.0.1/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.egg and /tmp/WwBlO9ZnuM/astroid-1.3.8/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.egg differ Binary files /tmp/tehDuGV_EZ/astroid-1.0.1/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.zip and /tmp/WwBlO9ZnuM/astroid-1.3.8/astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.zip differ diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/noendingnewline.py astroid-1.3.8/astroid/tests/testdata/python3/data/noendingnewline.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/noendingnewline.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/noendingnewline.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,36 @@ +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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/nonregr.py astroid-1.3.8/astroid/tests/testdata/python3/data/nonregr.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/nonregr.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/nonregr.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,57 @@ + + +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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/notall.py astroid-1.3.8/astroid/tests/testdata/python3/data/notall.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/notall.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/notall.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,8 @@ + +name = 'a' +_bla = 2 +other = 'o' +class Aaa: pass + +def func(): print('yo') + diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/package/absimport.py astroid-1.3.8/astroid/tests/testdata/python3/data/package/absimport.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/package/absimport.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/package/absimport.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,6 @@ +from __future__ import absolute_import, print_function +import import_package_subpackage_module # fail +print(import_package_subpackage_module) + +from . import hello as hola + diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/package/hello.py astroid-1.3.8/astroid/tests/testdata/python3/data/package/hello.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/package/hello.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/package/hello.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,2 @@ +"""hello module""" + diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py astroid-1.3.8/astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,49 @@ +# 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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/package/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/package/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/package/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/package/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,4 @@ +"""package's __init__ file""" + + +from . import subpackage diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/package/subpackage/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/package/subpackage/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/package/subpackage/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/package/subpackage/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +"""package.subpackage""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/package/subpackage/module.py astroid-1.3.8/astroid/tests/testdata/python3/data/package/subpackage/module.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/package/subpackage/module.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/package/subpackage/module.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +"""package.subpackage.module""" diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/recursion.py astroid-1.3.8/astroid/tests/testdata/python3/data/recursion.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/recursion.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/recursion.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,3 @@ +""" For issue #25 """ +class Base(object): + pass \ No newline at end of file diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/SSL1/Connection1.py astroid-1.3.8/astroid/tests/testdata/python3/data/SSL1/Connection1.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/SSL1/Connection1.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/SSL1/Connection1.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,14 @@ +"""M2Crypto.SSL.Connection + +Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" + +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 -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/SSL1/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/SSL1/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/SSL1/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/SSL1/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +from .Connection1 import Connection diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/suppliermodule_test.py astroid-1.3.8/astroid/tests/testdata/python3/data/suppliermodule_test.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/suppliermodule_test.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/suppliermodule_test.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,13 @@ +""" file suppliermodule.py """ + +class NotImplemented(Exception): + pass + +class Interface: + def get_value(self): + raise NotImplemented() + + def set_value(self, value): + raise NotImplemented() + +class DoNothing : pass diff -Nru astroid-1.0.1/astroid/tests/testdata/python3/data/unicode_package/__init__.py astroid-1.3.8/astroid/tests/testdata/python3/data/unicode_package/__init__.py --- astroid-1.0.1/astroid/tests/testdata/python3/data/unicode_package/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/testdata/python3/data/unicode_package/__init__.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1 @@ +x = "șțîâ" \ No newline at end of file diff -Nru astroid-1.0.1/astroid/tests/unittest_brain.py astroid-1.3.8/astroid/tests/unittest_brain.py --- astroid-1.0.1/astroid/tests/unittest_brain.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_brain.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,226 @@ +# Copyright 2013 Google Inc. All Rights Reserved. +# +# This file is part of astroid. +# +# logilab-astng is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# logilab-astng is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with logilab-astng. If not, see . +"""Tests for basic functionality in astroid.brain.""" +import sys +import unittest + +from astroid import MANAGER +from astroid import bases +from astroid import nodes +from astroid import test_utils +import astroid + +import six + + +try: + import nose # pylint: disable=unused-import + HAS_NOSE = True +except ImportError: + HAS_NOSE = False + + +class HashlibTest(unittest.TestCase): + def test_hashlib(self): + """Tests that brain extensions for hashlib work.""" + hashlib_module = MANAGER.ast_from_module_name('hashlib') + for class_name in ['md5', 'sha1']: + class_obj = hashlib_module[class_name] + self.assertIn('update', class_obj) + self.assertIn('digest', class_obj) + self.assertIn('hexdigest', class_obj) + 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) + 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) + + +class NamedTupleTest(unittest.TestCase): + def test_namedtuple_base(self): + klass = test_utils.extract_node(""" + from collections import namedtuple + + class X(namedtuple("X", ["a", "b", "c"])): + pass + """) + self.assertEqual( + [anc.name for anc in klass.ancestors()], + ['X', 'tuple', 'object']) + for anc in klass.ancestors(): + self.assertFalse(anc.parent is None) + + def test_namedtuple_inference(self): + klass = test_utils.extract_node(""" + from collections import namedtuple + + name = "X" + fields = ["a", "b", "c"] + class X(namedtuple(name, fields)): + pass + """) + for base in klass.ancestors(): + if base.name == 'X': + break + self.assertSetEqual({"a", "b", "c"}, set(base.instance_attrs)) + + def test_namedtuple_inference_failure(self): + klass = test_utils.extract_node(""" + from collections import namedtuple + + def foo(fields): + return __(namedtuple("foo", fields)) + """) + self.assertIs(bases.YES, next(klass.infer())) + + + @unittest.skipIf(sys.version_info[0] > 2, + 'namedtuple inference is broken on Python 3') + def test_namedtuple_advanced_inference(self): + # urlparse return an object of class ParseResult, which has a + # namedtuple call and a mixin as base classes + result = test_utils.extract_node(""" + import urlparse + + result = __(urlparse.urlparse('gopher://')) + """) + instance = next(result.infer()) + self.assertEqual(len(instance.getattr('scheme')), 1) + self.assertEqual(len(instance.getattr('port')), 1) + with self.assertRaises(astroid.NotFoundError): + instance.getattr('foo') + + +class ModuleExtenderTest(unittest.TestCase): + def testExtensionModules(self): + for extender, _ in MANAGER.transforms[nodes.Module]: + n = nodes.Module('__main__', None) + extender(n) + + +@unittest.skipUnless(HAS_NOSE, "This test requires nose library.") +class NoseBrainTest(unittest.TestCase): + + def test_nose_tools(self): + methods = test_utils.extract_node(""" + from nose.tools import assert_equal + from nose.tools import assert_true + assert_equal = assert_equal #@ + assert_true = assert_true #@ + """) + + assert_equal = next(methods[0].value.infer()) + assert_true = next(methods[1].value.infer()) + + self.assertIsInstance(assert_equal, astroid.BoundMethod) + self.assertIsInstance(assert_true, astroid.BoundMethod) + self.assertEqual(assert_equal.qname(), + 'unittest.case.TestCase.assertEqual') + self.assertEqual(assert_true.qname(), + 'unittest.case.TestCase.assertTrue') +class SixBrainTest(unittest.TestCase): + + def test_attribute_access(self): + ast_nodes = test_utils.extract_node(''' + import six + six.moves.http_client #@ + six.moves.urllib_parse #@ + six.moves.urllib_error #@ + six.moves.urllib.request #@ + ''') + http_client = next(ast_nodes[0].infer()) + self.assertIsInstance(http_client, nodes.Module) + self.assertEqual(http_client.name, + 'http.client' if six.PY3 else 'httplib') + + urllib_parse = next(ast_nodes[1].infer()) + if six.PY3: + self.assertIsInstance(urllib_parse, nodes.Module) + self.assertEqual(urllib_parse.name, 'urllib.parse') + else: + # On Python 2, this is a fake module, the same behaviour + # being mimicked in brain's tip for six.moves. + self.assertIsInstance(urllib_parse, astroid.Instance) + urljoin = next(urllib_parse.igetattr('urljoin')) + urlencode = next(urllib_parse.igetattr('urlencode')) + if six.PY2: + # In reality it's a function, but our implementations + # transforms it into a method. + self.assertIsInstance(urljoin, astroid.BoundMethod) + self.assertEqual(urljoin.qname(), 'urlparse.urljoin') + self.assertIsInstance(urlencode, astroid.BoundMethod) + self.assertEqual(urlencode.qname(), 'urllib.urlencode') + else: + self.assertIsInstance(urljoin, nodes.Function) + self.assertEqual(urljoin.qname(), 'urllib.parse.urljoin') + self.assertIsInstance(urlencode, nodes.Function) + self.assertEqual(urlencode.qname(), 'urllib.parse.urlencode') + + urllib_error = next(ast_nodes[2].infer()) + if six.PY3: + self.assertIsInstance(urllib_error, nodes.Module) + self.assertEqual(urllib_error.name, 'urllib.error') + else: + # On Python 2, this is a fake module, the same behaviour + # being mimicked in brain's tip for six.moves. + self.assertIsInstance(urllib_error, astroid.Instance) + urlerror = next(urllib_error.igetattr('URLError')) + self.assertIsInstance(urlerror, nodes.Class) + content_too_short = next(urllib_error.igetattr('ContentTooShortError')) + self.assertIsInstance(content_too_short, nodes.Class) + + urllib_request = next(ast_nodes[3].infer()) + if six.PY3: + self.assertIsInstance(urllib_request, nodes.Module) + self.assertEqual(urllib_request.name, 'urllib.request') + else: + self.assertIsInstance(urllib_request, astroid.Instance) + urlopen = next(urllib_request.igetattr('urlopen')) + urlretrieve = next(urllib_request.igetattr('urlretrieve')) + if six.PY2: + # In reality it's a function, but our implementations + # transforms it into a method. + self.assertIsInstance(urlopen, astroid.BoundMethod) + self.assertEqual(urlopen.qname(), 'urllib2.urlopen') + self.assertIsInstance(urlretrieve, astroid.BoundMethod) + self.assertEqual(urlretrieve.qname(), 'urllib.urlretrieve') + else: + self.assertIsInstance(urlopen, nodes.Function) + self.assertEqual(urlopen.qname(), 'urllib.request.urlopen') + self.assertIsInstance(urlretrieve, nodes.Function) + self.assertEqual(urlretrieve.qname(), 'urllib.request.urlretrieve') + + def test_from_imports(self): + ast_node = test_utils.extract_node(''' + from six.moves import http_client + http_client.HTTPSConnection #@ + ''') + inferred = next(ast_node.infer()) + self.assertIsInstance(inferred, nodes.Class) + if six.PY3: + qname = 'http.client.HTTPSConnection' + else: + qname = 'httplib.HTTPSConnection' + self.assertEqual(inferred.qname(), qname) + + + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_builder.py astroid-1.3.8/astroid/tests/unittest_builder.py --- astroid-1.0.1/astroid/tests/unittest_builder.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_builder.py 2015-08-02 19:35:55.000000000 +0000 @@ -0,0 +1,759 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""tests for the astroid builder and rebuilder module""" + +import os +import sys +import unittest + +from astroid import builder, nodes, InferenceError, NotFoundError +from astroid.bases import YES, BUILTINS +from astroid.manager import AstroidManager +from astroid import test_utils +from astroid.tests import resources + +MANAGER = AstroidManager() +IS_PY3 = sys.version_info[0] == 3 + + +class FromToLineNoTest(unittest.TestCase): + + def setUp(self): + self.astroid = resources.build_file('data/format.py') + + def test_callfunc_lineno(self): + stmts = self.astroid.body + # on line 4: + # function('aeozrijz\ + # earzer', hop) + discard = stmts[0] + self.assertIsInstance(discard, nodes.Discard) + self.assertEqual(discard.fromlineno, 4) + self.assertEqual(discard.tolineno, 5) + callfunc = discard.value + self.assertIsInstance(callfunc, nodes.CallFunc) + self.assertEqual(callfunc.fromlineno, 4) + self.assertEqual(callfunc.tolineno, 5) + name = callfunc.func + self.assertIsInstance(name, nodes.Name) + self.assertEqual(name.fromlineno, 4) + self.assertEqual(name.tolineno, 4) + strarg = callfunc.args[0] + self.assertIsInstance(strarg, nodes.Const) + if hasattr(sys, 'pypy_version_info'): + lineno = 4 + else: + lineno = 5 # no way for this one in CPython (is 4 actually) + self.assertEqual(strarg.fromlineno, lineno) + self.assertEqual(strarg.tolineno, lineno) + namearg = callfunc.args[1] + self.assertIsInstance(namearg, nodes.Name) + self.assertEqual(namearg.fromlineno, 5) + self.assertEqual(namearg.tolineno, 5) + # on line 10: + # fonction(1, + # 2, + # 3, + # 4) + discard = stmts[2] + self.assertIsInstance(discard, nodes.Discard) + self.assertEqual(discard.fromlineno, 10) + self.assertEqual(discard.tolineno, 13) + callfunc = discard.value + self.assertIsInstance(callfunc, nodes.CallFunc) + self.assertEqual(callfunc.fromlineno, 10) + self.assertEqual(callfunc.tolineno, 13) + name = callfunc.func + self.assertIsInstance(name, nodes.Name) + self.assertEqual(name.fromlineno, 10) + self.assertEqual(name.tolineno, 10) + for i, arg in enumerate(callfunc.args): + self.assertIsInstance(arg, nodes.Const) + self.assertEqual(arg.fromlineno, 10+i) + self.assertEqual(arg.tolineno, 10+i) + + def test_function_lineno(self): + stmts = self.astroid.body + # on line 15: + # def definition(a, + # b, + # c): + # return a + b + c + function = stmts[3] + self.assertIsInstance(function, nodes.Function) + self.assertEqual(function.fromlineno, 15) + self.assertEqual(function.tolineno, 18) + return_ = function.body[0] + self.assertIsInstance(return_, nodes.Return) + self.assertEqual(return_.fromlineno, 18) + self.assertEqual(return_.tolineno, 18) + if sys.version_info < (3, 0): + self.assertEqual(function.blockstart_tolineno, 17) + else: + self.skipTest('FIXME http://bugs.python.org/issue10445 ' + '(no line number on function args)') + + def test_decorated_function_lineno(self): + astroid = test_utils.build_module(''' + @decorator + def function( + arg): + print (arg) + ''', __name__) + function = astroid['function'] + self.assertEqual(function.fromlineno, 3) # XXX discussable, but that's what is expected by pylint right now + self.assertEqual(function.tolineno, 5) + self.assertEqual(function.decorators.fromlineno, 2) + self.assertEqual(function.decorators.tolineno, 2) + if sys.version_info < (3, 0): + self.assertEqual(function.blockstart_tolineno, 4) + else: + self.skipTest('FIXME http://bugs.python.org/issue10445 ' + '(no line number on function args)') + + + def test_class_lineno(self): + stmts = self.astroid.body + # on line 20: + # class debile(dict, + # object): + # pass + class_ = stmts[4] + self.assertIsInstance(class_, nodes.Class) + self.assertEqual(class_.fromlineno, 20) + self.assertEqual(class_.tolineno, 22) + self.assertEqual(class_.blockstart_tolineno, 21) + pass_ = class_.body[0] + self.assertIsInstance(pass_, nodes.Pass) + self.assertEqual(pass_.fromlineno, 22) + self.assertEqual(pass_.tolineno, 22) + + def test_if_lineno(self): + stmts = self.astroid.body + # on line 20: + # if aaaa: pass + # else: + # aaaa,bbbb = 1,2 + # aaaa,bbbb = bbbb,aaaa + if_ = stmts[5] + self.assertIsInstance(if_, nodes.If) + self.assertEqual(if_.fromlineno, 24) + self.assertEqual(if_.tolineno, 27) + self.assertEqual(if_.blockstart_tolineno, 24) + self.assertEqual(if_.orelse[0].fromlineno, 26) + self.assertEqual(if_.orelse[1].tolineno, 27) + + def test_for_while_lineno(self): + for code in (''' + for a in range(4): + print (a) + break + else: + print ("bouh") + ''', ''' + while a: + print (a) + break + else: + print ("bouh") + '''): + astroid = test_utils.build_module(code, __name__) + stmt = astroid.body[0] + self.assertEqual(stmt.fromlineno, 2) + self.assertEqual(stmt.tolineno, 6) + self.assertEqual(stmt.blockstart_tolineno, 2) + self.assertEqual(stmt.orelse[0].fromlineno, 6) # XXX + self.assertEqual(stmt.orelse[0].tolineno, 6) + + def test_try_except_lineno(self): + astroid = test_utils.build_module(''' + try: + print (a) + except: + pass + else: + print ("bouh") + ''', __name__) + try_ = astroid.body[0] + self.assertEqual(try_.fromlineno, 2) + self.assertEqual(try_.tolineno, 7) + self.assertEqual(try_.blockstart_tolineno, 2) + self.assertEqual(try_.orelse[0].fromlineno, 7) # XXX + self.assertEqual(try_.orelse[0].tolineno, 7) + hdlr = try_.handlers[0] + self.assertEqual(hdlr.fromlineno, 4) + self.assertEqual(hdlr.tolineno, 5) + self.assertEqual(hdlr.blockstart_tolineno, 4) + + + def test_try_finally_lineno(self): + astroid = test_utils.build_module(''' + try: + print (a) + finally: + print ("bouh") + ''', __name__) + try_ = astroid.body[0] + self.assertEqual(try_.fromlineno, 2) + self.assertEqual(try_.tolineno, 5) + self.assertEqual(try_.blockstart_tolineno, 2) + self.assertEqual(try_.finalbody[0].fromlineno, 5) # XXX + self.assertEqual(try_.finalbody[0].tolineno, 5) + + + def test_try_finally_25_lineno(self): + astroid = test_utils.build_module(''' + try: + print (a) + except: + pass + finally: + print ("bouh") + ''', __name__) + try_ = astroid.body[0] + self.assertEqual(try_.fromlineno, 2) + self.assertEqual(try_.tolineno, 7) + self.assertEqual(try_.blockstart_tolineno, 2) + self.assertEqual(try_.finalbody[0].fromlineno, 7) # XXX + self.assertEqual(try_.finalbody[0].tolineno, 7) + + + def test_with_lineno(self): + astroid = test_utils.build_module(''' + from __future__ import with_statement + with file("/tmp/pouet") as f: + print (f) + ''', __name__) + with_ = astroid.body[1] + self.assertEqual(with_.fromlineno, 3) + self.assertEqual(with_.tolineno, 4) + self.assertEqual(with_.blockstart_tolineno, 3) + + +class BuilderTest(unittest.TestCase): + + def setUp(self): + self.builder = builder.AstroidBuilder() + + def test_data_build_null_bytes(self): + with self.assertRaises(builder.AstroidBuildingException): + self.builder.string_build('\x00') + + 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(builder.AstroidBuildingException): + resources.build_file('data/inexistant.py') + + def test_inspect_build0(self): + """test astroid tree build from a living object""" + builtin_ast = MANAGER.ast_from_module_name(BUILTINS) + if not IS_PY3: + fclass = builtin_ast['file'] + self.assertIn('name', fclass) + self.assertIn('mode', fclass) + self.assertIn('read', fclass) + self.assertTrue(fclass.newstyle) + self.assertTrue(fclass.pytype(), '%s.type' % BUILTINS) + self.assertIsInstance(fclass['read'], nodes.Function) + # check builtin function has args.args == None + dclass = builtin_ast['dict'] + self.assertIsNone(dclass['has_key'].args.args) + # just check type and object are there + builtin_ast.getattr('type') + objectastroid = builtin_ast.getattr('object')[0] + self.assertIsInstance(objectastroid.getattr('__new__')[0], nodes.Function) + # check open file alias + builtin_ast.getattr('open') + # check 'help' is there (defined dynamically by site.py) + builtin_ast.getattr('help') + # check property has __init__ + pclass = builtin_ast['property'] + self.assertIn('__init__', pclass) + self.assertIsInstance(builtin_ast['None'], nodes.Const) + self.assertIsInstance(builtin_ast['True'], nodes.Const) + self.assertIsInstance(builtin_ast['False'], nodes.Const) + if IS_PY3: + self.assertIsInstance(builtin_ast['Exception'], nodes.Class) + self.assertIsInstance(builtin_ast['NotImplementedError'], nodes.Class) + else: + self.assertIsInstance(builtin_ast['Exception'], nodes.From) + self.assertIsInstance(builtin_ast['NotImplementedError'], nodes.From) + + def test_inspect_build1(self): + time_ast = MANAGER.ast_from_module_name('time') + self.assertTrue(time_ast) + self.assertEqual(time_ast['time'].args.defaults, []) + + def test_inspect_build2(self): + """test astroid tree build from a living object""" + try: + from mx import DateTime + except ImportError: + self.skipTest('test skipped: mxDateTime is not available') + else: + dt_ast = self.builder.inspect_build(DateTime) + dt_ast.getattr('DateTime') + # this one is failing since DateTimeType.__module__ = 'builtins' ! + #dt_ast.getattr('DateTimeType') + + def test_inspect_build3(self): + self.builder.inspect_build(unittest) + + @test_utils.require_version(maxver='3.0') + def test_inspect_build_instance(self): + """test astroid tree build from a living object""" + import exceptions + builtin_ast = self.builder.inspect_build(exceptions) + fclass = builtin_ast['OSError'] + # things like OSError.strerror are now (2.5) data descriptors on the + # class instead of entries in the __dict__ of an instance + container = fclass + self.assertIn('errno', container) + self.assertIn('strerror', container) + self.assertIn('filename', container) + + def test_inspect_build_type_object(self): + builtin_ast = MANAGER.ast_from_module_name(BUILTINS) + + infered = list(builtin_ast.igetattr('object')) + self.assertEqual(len(infered), 1) + infered = infered[0] + self.assertEqual(infered.name, 'object') + infered.as_string() # no crash test + + infered = list(builtin_ast.igetattr('type')) + self.assertEqual(len(infered), 1) + infered = infered[0] + self.assertEqual(infered.name, 'type') + infered.as_string() # no crash test + + def test_inspect_transform_module(self): + # ensure no cached version of the time module + MANAGER._mod_file_cache.pop(('time', None), None) + MANAGER.astroid_cache.pop('time', None) + def transform_time(node): + if node.name == 'time': + node.transformed = True + MANAGER.register_transform(nodes.Module, transform_time) + try: + time_ast = MANAGER.ast_from_module_name('time') + self.assertTrue(getattr(time_ast, 'transformed', False)) + finally: + MANAGER.unregister_transform(nodes.Module, transform_time) + + def test_package_name(self): + """test base properties and method of a astroid module""" + datap = resources.build_file('data/__init__.py', 'data') + self.assertEqual(datap.name, 'data') + self.assertEqual(datap.package, 1) + datap = resources.build_file('data/__init__.py', 'data.__init__') + self.assertEqual(datap.name, 'data') + self.assertEqual(datap.package, 1) + + def test_yield_parent(self): + """check if we added discard nodes as yield parent (w/ compiler)""" + code = """ + def yiell(): #@ + yield 0 + if noe: + yield more + """ + func = test_utils.extract_node(code) + self.assertIsInstance(func, nodes.Function) + stmt = func.body[0] + self.assertIsInstance(stmt, nodes.Discard) + self.assertIsInstance(stmt.value, nodes.Yield) + self.assertIsInstance(func.body[1].body[0], nodes.Discard) + self.assertIsInstance(func.body[1].body[0].value, nodes.Yield) + + def test_object(self): + obj_ast = self.builder.inspect_build(object) + self.assertIn('__setattr__', obj_ast) + + def test_newstyle_detection(self): + data = ''' + class A: + "old style" + + class B(A): + "old style" + + class C(object): + "new style" + + class D(C): + "new style" + + __metaclass__ = type + + class E(A): + "old style" + + class F: + "new style" + ''' + mod_ast = test_utils.build_module(data, __name__) + if IS_PY3: + self.assertTrue(mod_ast['A'].newstyle) + self.assertTrue(mod_ast['B'].newstyle) + self.assertTrue(mod_ast['E'].newstyle) + else: + self.assertFalse(mod_ast['A'].newstyle) + self.assertFalse(mod_ast['B'].newstyle) + self.assertFalse(mod_ast['E'].newstyle) + self.assertTrue(mod_ast['C'].newstyle) + self.assertTrue(mod_ast['D'].newstyle) + self.assertTrue(mod_ast['F'].newstyle) + + def test_globals(self): + data = ''' + CSTE = 1 + + def update_global(): + global CSTE + CSTE += 1 + + def global_no_effect(): + global CSTE2 + print (CSTE) + ''' + astroid = test_utils.build_module(data, __name__) + self.assertEqual(len(astroid.getattr('CSTE')), 2) + self.assertIsInstance(astroid.getattr('CSTE')[0], nodes.AssName) + self.assertEqual(astroid.getattr('CSTE')[0].fromlineno, 2) + self.assertEqual(astroid.getattr('CSTE')[1].fromlineno, 6) + with self.assertRaises(NotFoundError): + astroid.getattr('CSTE2') + with self.assertRaises(InferenceError): + next(astroid['global_no_effect'].ilookup('CSTE2')) + + def test_socket_build(self): + import socket + astroid = self.builder.module_build(socket) + # XXX just check the first one. Actually 3 objects are inferred (look at + # the socket module) but the last one as those attributes dynamically + # set and astroid is missing this. + for fclass in astroid.igetattr('socket'): + #print fclass.root().name, fclass.name, fclass.lineno + self.assertIn('connect', fclass) + self.assertIn('send', fclass) + self.assertIn('close', fclass) + break + + def test_gen_expr_var_scope(self): + data = 'l = list(n for n in range(10))\n' + astroid = test_utils.build_module(data, __name__) + # n unavailable outside gen expr scope + self.assertNotIn('n', astroid) + # test n is inferable anyway + n = test_utils.get_name_node(astroid, 'n') + self.assertIsNot(n.scope(), astroid) + self.assertEqual([i.__class__ for i in n.infer()], + [YES.__class__]) + + def test_no_future_imports(self): + mod = test_utils.build_module("import sys") + self.assertEqual(set(), mod.future_imports) + + def test_future_imports(self): + mod = test_utils.build_module("from __future__ import print_function") + self.assertEqual(set(['print_function']), mod.future_imports) + + def test_two_future_imports(self): + mod = test_utils.build_module(""" + from __future__ import print_function + from __future__ import absolute_import + """) + self.assertEqual(set(['print_function', 'absolute_import']), mod.future_imports) + + def test_infered_build(self): + code = ''' + class A: pass + A.type = "class" + + def A_ass_type(self): + print (self) + A.ass_type = A_ass_type + ''' + astroid = test_utils.build_module(code) + lclass = list(astroid.igetattr('A')) + self.assertEqual(len(lclass), 1) + lclass = lclass[0] + self.assertIn('ass_type', lclass.locals) + self.assertIn('type', lclass.locals) + + def test_augassign_attr(self): + test_utils.build_module(""" + class Counter: + v = 0 + def inc(self): + self.v += 1 + """, __name__) + # TODO: Check self.v += 1 generate AugAssign(AssAttr(...)), + # not AugAssign(GetAttr(AssName...)) + + def test_infered_dont_pollute(self): + code = ''' + def func(a=None): + a.custom_attr = 0 + def func2(a={}): + a.custom_attr = 0 + ''' + test_utils.build_module(code) + nonetype = nodes.const_factory(None) + self.assertNotIn('custom_attr', nonetype.locals) + self.assertNotIn('custom_attr', nonetype.instance_attrs) + nonetype = nodes.const_factory({}) + self.assertNotIn('custom_attr', nonetype.locals) + self.assertNotIn('custom_attr', nonetype.instance_attrs) + + def test_asstuple(self): + code = 'a, b = range(2)' + astroid = test_utils.build_module(code) + self.assertIn('b', astroid.locals) + code = ''' + def visit_if(self, node): + node.test, body = node.tests[0] + ''' + astroid = test_utils.build_module(code) + self.assertIn('body', astroid['visit_if'].locals) + + def test_build_constants(self): + '''test expected values of constants after rebuilding''' + code = ''' + def func(): + return None + return + return 'None' + ''' + astroid = test_utils.build_module(code) + none, nothing, chain = [ret.value for ret in astroid.body[0].body] + self.assertIsInstance(none, nodes.Const) + self.assertIsNone(none.value) + self.assertIsNone(nothing) + self.assertIsInstance(chain, nodes.Const) + self.assertEqual(chain.value, 'None') + + def test_lgc_classproperty(self): + '''test expected values of constants after rebuilding''' + code = ''' + from logilab.common.decorators import classproperty + + class A(object): + @classproperty + def hop(cls): #@ + return None + ''' + method = test_utils.extract_node(code) + self.assertEqual('classmethod', method.type) + + +class FileBuildTest(unittest.TestCase): + def setUp(self): + self.module = resources.build_file('data/module.py', 'data.module') + + def test_module_base_props(self): + """test base properties and method of a astroid module""" + module = self.module + self.assertEqual(module.name, 'data.module') + self.assertEqual(module.doc, "test module for astroid\n") + self.assertEqual(module.fromlineno, 0) + self.assertIsNone(module.parent) + self.assertEqual(module.frame(), module) + self.assertEqual(module.root(), module) + self.assertEqual(module.file, os.path.abspath(resources.find('data/module.py'))) + self.assertEqual(module.pure_python, 1) + self.assertEqual(module.package, 0) + self.assertFalse(module.is_statement) + self.assertEqual(module.statement(), module) + self.assertEqual(module.statement(), module) + + def test_module_locals(self): + """test the 'locals' dictionary of a astroid module""" + module = self.module + _locals = module.locals + self.assertIs(_locals, module.globals) + keys = sorted(_locals.keys()) + should = ['MY_DICT', 'YO', 'YOUPI', + '__revision__', 'global_access', 'modutils', 'four_args', + 'os', 'redirect', 'pb', 'LocalsVisitor', 'ASTWalker'] + should.sort() + self.assertEqual(keys, should) + + def test_function_base_props(self): + """test base properties and method of a astroid function""" + module = self.module + function = module['global_access'] + self.assertEqual(function.name, 'global_access') + self.assertEqual(function.doc, 'function test') + self.assertEqual(function.fromlineno, 11) + self.assertTrue(function.parent) + self.assertEqual(function.frame(), function) + self.assertEqual(function.parent.frame(), module) + self.assertEqual(function.root(), module) + self.assertEqual([n.name for n in function.args.args], ['key', 'val']) + self.assertEqual(function.type, 'function') + + def test_function_locals(self): + """test the 'locals' dictionary of a astroid function""" + _locals = self.module['global_access'].locals + self.assertEqual(len(_locals), 4) + keys = sorted(_locals.keys()) + self.assertEqual(keys, ['i', 'key', 'local', 'val']) + + def test_class_base_props(self): + """test base properties and method of a astroid class""" + module = self.module + klass = module['YO'] + self.assertEqual(klass.name, 'YO') + self.assertEqual(klass.doc, 'hehe') + self.assertEqual(klass.fromlineno, 25) + self.assertTrue(klass.parent) + self.assertEqual(klass.frame(), klass) + self.assertEqual(klass.parent.frame(), module) + self.assertEqual(klass.root(), module) + self.assertEqual(klass.basenames, []) + if IS_PY3: + self.assertTrue(klass.newstyle) + else: + self.assertFalse(klass.newstyle) + + def test_class_locals(self): + """test the 'locals' dictionary of a astroid class""" + module = self.module + klass1 = module['YO'] + locals1 = klass1.locals + keys = sorted(locals1.keys()) + self.assertEqual(keys, ['__init__', 'a']) + klass2 = module['YOUPI'] + locals2 = klass2.locals + keys = locals2.keys() + self.assertEqual(sorted(keys), + ['__init__', 'class_attr', 'class_method', + 'method', 'static_method']) + + def test_class_instance_attrs(self): + module = self.module + klass1 = module['YO'] + klass2 = module['YOUPI'] + self.assertEqual(list(klass1.instance_attrs.keys()), ['yo']) + self.assertEqual(list(klass2.instance_attrs.keys()), ['member']) + + def test_class_basenames(self): + module = self.module + klass1 = module['YO'] + klass2 = module['YOUPI'] + self.assertEqual(klass1.basenames, []) + self.assertEqual(klass2.basenames, ['YO']) + + def test_method_base_props(self): + """test base properties and method of a astroid method""" + klass2 = self.module['YOUPI'] + # "normal" method + method = klass2['method'] + self.assertEqual(method.name, 'method') + self.assertEqual([n.name for n in method.args.args], ['self']) + self.assertEqual(method.doc, 'method test') + self.assertEqual(method.fromlineno, 47) + self.assertEqual(method.type, 'method') + # class method + method = klass2['class_method'] + self.assertEqual([n.name for n in method.args.args], ['cls']) + self.assertEqual(method.type, 'classmethod') + # static method + method = klass2['static_method'] + self.assertEqual(method.args.args, []) + self.assertEqual(method.type, 'staticmethod') + + def test_method_locals(self): + """test the 'locals' dictionary of a astroid method""" + method = self.module['YOUPI']['method'] + _locals = method.locals + keys = sorted(_locals) + if sys.version_info < (3, 0): + self.assertEqual(len(_locals), 5) + self.assertEqual(keys, ['a', 'autre', 'b', 'local', 'self']) + else:# ListComp variables are no more accessible outside + self.assertEqual(len(_locals), 3) + self.assertEqual(keys, ['autre', 'local', 'self']) + + +class ModuleBuildTest(resources.SysPathSetup, FileBuildTest): + + def setUp(self): + super(ModuleBuildTest, self).setUp() + abuilder = builder.AstroidBuilder() + import data.module + self.module = abuilder.module_build(data.module, 'data.module') + +@unittest.skipIf(IS_PY3, "guess_encoding not used on Python 3") +class TestGuessEncoding(unittest.TestCase): + def setUp(self): + self.guess_encoding = builder._guess_encoding + + def testEmacs(self): + e = self.guess_encoding('# -*- coding: UTF-8 -*-') + self.assertEqual(e, 'UTF-8') + e = self.guess_encoding('# -*- coding:UTF-8 -*-') + self.assertEqual(e, 'UTF-8') + e = self.guess_encoding(''' + ### -*- coding: ISO-8859-1 -*- + ''') + self.assertEqual(e, 'ISO-8859-1') + e = self.guess_encoding(''' + + ### -*- coding: ISO-8859-1 -*- + ''') + self.assertIsNone(e) + + def testVim(self): + e = self.guess_encoding('# vim:fileencoding=UTF-8') + self.assertEqual(e, 'UTF-8') + e = self.guess_encoding(''' + ### vim:fileencoding=ISO-8859-1 + ''') + self.assertEqual(e, 'ISO-8859-1') + e = self.guess_encoding(''' + + ### vim:fileencoding= ISO-8859-1 + ''') + self.assertIsNone(e) + + def test_wrong_coding(self): + # setting "coding" varaible + e = self.guess_encoding("coding = UTF-8") + self.assertIsNone(e) + # setting a dictionnary entry + e = self.guess_encoding("coding:UTF-8") + self.assertIsNone(e) + # setting an arguement + e = self.guess_encoding("def do_something(a_word_with_coding=None):") + self.assertIsNone(e) + + def testUTF8(self): + e = self.guess_encoding('\xef\xbb\xbf any UTF-8 data') + self.assertEqual(e, 'UTF-8') + e = self.guess_encoding(' any UTF-8 data \xef\xbb\xbf') + self.assertIsNone(e) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_inference.py astroid-1.3.8/astroid/tests/unittest_inference.py --- astroid-1.0.1/astroid/tests/unittest_inference.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_inference.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,1644 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""tests for the astroid inference capabilities +""" +import sys +from functools import partial +import unittest + +import six + +from astroid import InferenceError, builder, nodes +from astroid.inference import infer_end as inference_infer_end +from astroid.bases import YES, Instance, BoundMethod, UnboundMethod,\ + path_wrapper, BUILTINS +from astroid import test_utils +from astroid.tests import resources + + +def get_node_of_class(start_from, klass): + return next(start_from.nodes_of_class(klass)) + +builder = builder.AstroidBuilder() + +if sys.version_info < (3, 0): + EXC_MODULE = 'exceptions' +else: + EXC_MODULE = BUILTINS + + +class InferenceUtilsTest(unittest.TestCase): + + def test_path_wrapper(self): + def infer_default(self, *args): + raise InferenceError + infer_default = path_wrapper(infer_default) + infer_end = path_wrapper(inference_infer_end) + with self.assertRaises(InferenceError): + next(infer_default(1)) + self.assertEqual(next(infer_end(1)), 1) + + +def _assertInferElts(node_type, self, node, elts): + infered = next(node.infer()) + self.assertIsInstance(infered, node_type) + self.assertEqual(sorted(elt.value for elt in infered.elts), + elts) + +def partialmethod(func, arg): + """similar to functools.partial but return a lambda instead of a class so returned value may be + turned into a method. + """ + return lambda *args, **kwargs: func(arg, *args, **kwargs) + +class InferenceTest(resources.SysPathSetup, unittest.TestCase): + + # additional assertInfer* method for builtin types + + def assertInferConst(self, node, expected): + infered = next(node.infer()) + self.assertIsInstance(infered, nodes.Const) + self.assertEqual(infered.value, expected) + + def assertInferDict(self, node, expected): + infered = next(node.infer()) + self.assertIsInstance(infered, nodes.Dict) + + elts = set([(key.value, value.value) + for (key, value) in infered.items]) + self.assertEqual(sorted(elts), sorted(expected.items())) + + assertInferTuple = partialmethod(_assertInferElts, nodes.Tuple) + assertInferList = partialmethod(_assertInferElts, nodes.List) + assertInferSet = partialmethod(_assertInferElts, nodes.Set) + + CODE = ''' + class C(object): + "new style" + attr = 4 + + def meth1(self, arg1, optarg=0): + var = object() + print ("yo", arg1, optarg) + self.iattr = "hop" + return var + + def meth2(self): + self.meth1(*self.meth3) + + def meth3(self, d=attr): + b = self.attr + c = self.iattr + return b, c + + ex = Exception("msg") + v = C().meth1(1) + m_unbound = C.meth1 + m_bound = C().meth1 + a, b, c = ex, 1, "bonjour" + [d, e, f] = [ex, 1.0, ("bonjour", v)] + g, h = f + i, (j, k) = "glup", f + + a, b= b, a # Gasp ! + ''' + + ast = test_utils.build_module(CODE, __name__) + + def test_module_inference(self): + infered = self.ast.infer() + obj = next(infered) + self.assertEqual(obj.name, __name__) + self.assertEqual(obj.root().name, __name__) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_class_inference(self): + infered = self.ast['C'].infer() + obj = next(infered) + self.assertEqual(obj.name, 'C') + self.assertEqual(obj.root().name, __name__) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_function_inference(self): + infered = self.ast['C']['meth1'].infer() + obj = next(infered) + self.assertEqual(obj.name, 'meth1') + self.assertEqual(obj.root().name, __name__) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_builtin_name_inference(self): + infered = self.ast['C']['meth1']['var'].infer() + var = next(infered) + self.assertEqual(var.name, 'object') + self.assertEqual(var.root().name, BUILTINS) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_tupleassign_name_inference(self): + infered = self.ast['a'].infer() + exc = next(infered) + self.assertIsInstance(exc, Instance) + self.assertEqual(exc.name, 'Exception') + self.assertEqual(exc.root().name, EXC_MODULE) + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast['b'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, 1) + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast['c'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, "bonjour") + self.assertRaises(StopIteration, partial(next, infered)) + + def test_listassign_name_inference(self): + infered = self.ast['d'].infer() + exc = next(infered) + self.assertIsInstance(exc, Instance) + self.assertEqual(exc.name, 'Exception') + self.assertEqual(exc.root().name, EXC_MODULE) + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast['e'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, 1.0) + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast['f'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Tuple) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_advanced_tupleassign_name_inference1(self): + infered = self.ast['g'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, "bonjour") + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast['h'].infer() + var = next(infered) + self.assertEqual(var.name, 'object') + self.assertEqual(var.root().name, BUILTINS) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_advanced_tupleassign_name_inference2(self): + infered = self.ast['i'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, u"glup") + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast['j'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, "bonjour") + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast['k'].infer() + var = next(infered) + self.assertEqual(var.name, 'object') + self.assertEqual(var.root().name, BUILTINS) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_swap_assign_inference(self): + infered = self.ast.locals['a'][1].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, 1) + self.assertRaises(StopIteration, partial(next, infered)) + infered = self.ast.locals['b'][1].infer() + exc = next(infered) + self.assertIsInstance(exc, Instance) + self.assertEqual(exc.name, 'Exception') + self.assertEqual(exc.root().name, EXC_MODULE) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_getattr_inference1(self): + infered = self.ast['ex'].infer() + exc = next(infered) + self.assertIsInstance(exc, Instance) + self.assertEqual(exc.name, 'Exception') + self.assertEqual(exc.root().name, EXC_MODULE) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_getattr_inference2(self): + infered = get_node_of_class(self.ast['C']['meth2'], nodes.Getattr).infer() + meth1 = next(infered) + self.assertEqual(meth1.name, 'meth1') + self.assertEqual(meth1.root().name, __name__) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_getattr_inference3(self): + infered = self.ast['C']['meth3']['b'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, 4) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_getattr_inference4(self): + infered = self.ast['C']['meth3']['c'].infer() + const = next(infered) + self.assertIsInstance(const, nodes.Const) + self.assertEqual(const.value, "hop") + self.assertRaises(StopIteration, partial(next, infered)) + + def test_callfunc_inference(self): + infered = self.ast['v'].infer() + meth1 = next(infered) + self.assertIsInstance(meth1, Instance) + self.assertEqual(meth1.name, 'object') + self.assertEqual(meth1.root().name, BUILTINS) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_unbound_method_inference(self): + infered = self.ast['m_unbound'].infer() + meth1 = next(infered) + self.assertIsInstance(meth1, UnboundMethod) + self.assertEqual(meth1.name, 'meth1') + self.assertEqual(meth1.parent.frame().name, 'C') + self.assertRaises(StopIteration, partial(next, infered)) + + def test_bound_method_inference(self): + infered = self.ast['m_bound'].infer() + meth1 = next(infered) + self.assertIsInstance(meth1, BoundMethod) + self.assertEqual(meth1.name, 'meth1') + self.assertEqual(meth1.parent.frame().name, 'C') + self.assertRaises(StopIteration, partial(next, infered)) + + def test_args_default_inference1(self): + optarg = test_utils.get_name_node(self.ast['C']['meth1'], 'optarg') + infered = optarg.infer() + obj1 = next(infered) + self.assertIsInstance(obj1, nodes.Const) + self.assertEqual(obj1.value, 0) + obj1 = next(infered) + self.assertIs(obj1, YES, obj1) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_args_default_inference2(self): + infered = self.ast['C']['meth3'].ilookup('d') + obj1 = next(infered) + self.assertIsInstance(obj1, nodes.Const) + self.assertEqual(obj1.value, 4) + obj1 = next(infered) + self.assertIs(obj1, YES, obj1) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_inference_restrictions(self): + infered = test_utils.get_name_node(self.ast['C']['meth1'], 'arg1').infer() + obj1 = next(infered) + self.assertIs(obj1, YES, obj1) + self.assertRaises(StopIteration, partial(next, infered)) + + def test_ancestors_inference(self): + code = ''' + class A(object): #@ + pass + + class A(A): #@ + pass + ''' + a1, a2 = test_utils.extract_node(code, __name__) + a2_ancestors = list(a2.ancestors()) + self.assertEqual(len(a2_ancestors), 2) + self.assertIs(a2_ancestors[0], a1) + + def test_ancestors_inference2(self): + code = ''' + class A(object): #@ + pass + + class B(A): #@ + pass + + class A(B): #@ + pass + ''' + a1, b, a2 = test_utils.extract_node(code, __name__) + a2_ancestors = list(a2.ancestors()) + self.assertEqual(len(a2_ancestors), 3) + self.assertIs(a2_ancestors[0], b) + self.assertIs(a2_ancestors[1], a1) + + + def test_f_arg_f(self): + code = ''' + def f(f=1): + return f + + a = f() + ''' + ast = test_utils.build_module(code, __name__) + a = ast['a'] + a_infered = a.infered() + self.assertEqual(a_infered[0].value, 1) + self.assertEqual(len(a_infered), 1) + + def test_exc_ancestors(self): + code = ''' + def f(): + raise __(NotImplementedError) + ''' + error = test_utils.extract_node(code, __name__) + nie = error.infered()[0] + self.assertIsInstance(nie, nodes.Class) + nie_ancestors = [c.name for c in nie.ancestors()] + if sys.version_info < (3, 0): + self.assertEqual(nie_ancestors, ['RuntimeError', 'StandardError', 'Exception', 'BaseException', 'object']) + else: + self.assertEqual(nie_ancestors, ['RuntimeError', 'Exception', 'BaseException', 'object']) + + def test_except_inference(self): + code = ''' + try: + print (hop) + except NameError as ex: + ex1 = ex + except Exception as ex: + ex2 = ex + raise + ''' + ast = test_utils.build_module(code, __name__) + ex1 = ast['ex1'] + ex1_infer = ex1.infer() + ex1 = next(ex1_infer) + self.assertIsInstance(ex1, Instance) + self.assertEqual(ex1.name, 'NameError') + self.assertRaises(StopIteration, partial(next, ex1_infer)) + ex2 = ast['ex2'] + ex2_infer = ex2.infer() + ex2 = next(ex2_infer) + self.assertIsInstance(ex2, Instance) + self.assertEqual(ex2.name, 'Exception') + self.assertRaises(StopIteration, partial(next, ex2_infer)) + + def test_del1(self): + code = ''' + del undefined_attr + ''' + delete = test_utils.extract_node(code, __name__) + self.assertRaises(InferenceError, delete.infer) + + def test_del2(self): + code = ''' + a = 1 + b = a + del a + c = a + a = 2 + d = a + ''' + ast = test_utils.build_module(code, __name__) + n = ast['b'] + n_infer = n.infer() + infered = next(n_infer) + self.assertIsInstance(infered, nodes.Const) + self.assertEqual(infered.value, 1) + self.assertRaises(StopIteration, partial(next, n_infer)) + n = ast['c'] + n_infer = n.infer() + self.assertRaises(InferenceError, partial(next, n_infer)) + n = ast['d'] + n_infer = n.infer() + infered = next(n_infer) + self.assertIsInstance(infered, nodes.Const) + self.assertEqual(infered.value, 2) + self.assertRaises(StopIteration, partial(next, n_infer)) + + def test_builtin_types(self): + code = ''' + l = [1] + t = (2,) + d = {} + s = '' + s2 = '_' + ''' + ast = test_utils.build_module(code, __name__) + n = ast['l'] + infered = next(n.infer()) + self.assertIsInstance(infered, nodes.List) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.getitem(0).value, 1) + self.assertIsInstance(infered._proxied, nodes.Class) + self.assertEqual(infered._proxied.name, 'list') + self.assertIn('append', infered._proxied.locals) + n = ast['t'] + infered = next(n.infer()) + self.assertIsInstance(infered, nodes.Tuple) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.getitem(0).value, 2) + self.assertIsInstance(infered._proxied, nodes.Class) + self.assertEqual(infered._proxied.name, 'tuple') + n = ast['d'] + infered = next(n.infer()) + self.assertIsInstance(infered, nodes.Dict) + self.assertIsInstance(infered, Instance) + self.assertIsInstance(infered._proxied, nodes.Class) + self.assertEqual(infered._proxied.name, 'dict') + self.assertIn('get', infered._proxied.locals) + n = ast['s'] + infered = next(n.infer()) + self.assertIsInstance(infered, nodes.Const) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.name, 'str') + self.assertIn('lower', infered._proxied.locals) + n = ast['s2'] + infered = next(n.infer()) + self.assertEqual(infered.getitem(0).value, '_') + + def test_builtin_types(self): + code = 's = {1}' + ast = test_utils.build_module(code, __name__) + n = ast['s'] + infered = next(n.infer()) + self.assertIsInstance(infered, nodes.Set) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.name, 'set') + self.assertIn('remove', infered._proxied.locals) + + @test_utils.require_version(maxver='3.0') + def test_unicode_type(self): + code = '''u = u""''' + ast = test_utils.build_module(code, __name__) + n = ast['u'] + infered = next(n.infer()) + self.assertIsInstance(infered, nodes.Const) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.name, 'unicode') + self.assertIn('lower', infered._proxied.locals) + + def test_descriptor_are_callable(self): + code = ''' + class A: + statm = staticmethod(open) + clsm = classmethod('whatever') + ''' + ast = test_utils.build_module(code, __name__) + statm = next(ast['A'].igetattr('statm')) + self.assertTrue(statm.callable()) + clsm = next(ast['A'].igetattr('clsm')) + self.assertTrue(clsm.callable()) + + def test_bt_ancestor_crash(self): + code = ''' + class Warning(Warning): + pass + ''' + ast = test_utils.build_module(code, __name__) + w = ast['Warning'] + ancestors = w.ancestors() + ancestor = next(ancestors) + self.assertEqual(ancestor.name, 'Warning') + self.assertEqual(ancestor.root().name, EXC_MODULE) + ancestor = next(ancestors) + self.assertEqual(ancestor.name, 'Exception') + self.assertEqual(ancestor.root().name, EXC_MODULE) + ancestor = next(ancestors) + self.assertEqual(ancestor.name, 'BaseException') + self.assertEqual(ancestor.root().name, EXC_MODULE) + ancestor = next(ancestors) + self.assertEqual(ancestor.name, 'object') + self.assertEqual(ancestor.root().name, BUILTINS) + self.assertRaises(StopIteration, partial(next, ancestors)) + + def test_qqch(self): + code = ''' + from astroid.modutils import load_module_from_name + xxx = load_module_from_name('__pkginfo__') + ''' + ast = test_utils.build_module(code, __name__) + xxx = ast['xxx'] + self.assertSetEqual({n.__class__ for n in xxx.infered()}, + {nodes.Const, YES.__class__}) + + def test_method_argument(self): + code = ''' + class ErudiEntitySchema: + """a entity has a type, a set of subject and or object relations""" + def __init__(self, e_type, **kwargs): + kwargs['e_type'] = e_type.capitalize().encode() + + def meth(self, e_type, *args, **kwargs): + kwargs['e_type'] = e_type.capitalize().encode() + print(args) + ''' + ast = test_utils.build_module(code, __name__) + arg = test_utils.get_name_node(ast['ErudiEntitySchema']['__init__'], 'e_type') + self.assertEqual([n.__class__ for n in arg.infer()], + [YES.__class__]) + arg = test_utils.get_name_node(ast['ErudiEntitySchema']['__init__'], 'kwargs') + self.assertEqual([n.__class__ for n in arg.infer()], + [nodes.Dict]) + arg = test_utils.get_name_node(ast['ErudiEntitySchema']['meth'], 'e_type') + self.assertEqual([n.__class__ for n in arg.infer()], + [YES.__class__]) + arg = test_utils.get_name_node(ast['ErudiEntitySchema']['meth'], 'args') + self.assertEqual([n.__class__ for n in arg.infer()], + [nodes.Tuple]) + arg = test_utils.get_name_node(ast['ErudiEntitySchema']['meth'], 'kwargs') + self.assertEqual([n.__class__ for n in arg.infer()], + [nodes.Dict]) + + def test_tuple_then_list(self): + code = ''' + def test_view(rql, vid, tags=()): + tags = list(tags) + __(tags).append(vid) + ''' + name = test_utils.extract_node(code, __name__) + it = name.infer() + tags = next(it) + self.assertIsInstance(tags, nodes.List) + self.assertEqual(tags.elts, []) + with self.assertRaises(StopIteration): + next(it) + + def test_mulassign_inference(self): + code = ''' + def first_word(line): + """Return the first word of a line""" + + return line.split()[0] + + def last_word(line): + """Return last word of a line""" + + return line.split()[-1] + + def process_line(word_pos): + """Silly function: returns (ok, callable) based on argument. + + For test purpose only. + """ + + if word_pos > 0: + return (True, first_word) + elif word_pos < 0: + return (True, last_word) + else: + return (False, None) + + if __name__ == '__main__': + + line_number = 0 + for a_line in file('test_callable.py'): + tupletest = process_line(line_number) + (ok, fct) = process_line(line_number) + if ok: + fct(a_line) + ''' + ast = test_utils.build_module(code, __name__) + self.assertEqual(len(list(ast['process_line'].infer_call_result( + None))), 3) + self.assertEqual(len(list(ast['tupletest'].infer())), 3) + values = ['Function(first_word)', 'Function(last_word)', 'Const(NoneType)'] + self.assertEqual([str(infered) + for infered in ast['fct'].infer()], values) + + def test_float_complex_ambiguity(self): + code = ''' + def no_conjugate_member(magic_flag): #@ + """should not raise E1101 on something.conjugate""" + if magic_flag: + something = 1.0 + else: + something = 1.0j + if isinstance(something, float): + return something + return __(something).conjugate() + ''' + func, retval = test_utils.extract_node(code, __name__) + self.assertEqual( + [i.value for i in func.ilookup('something')], + [1.0, 1.0j]) + self.assertEqual( + [i.value for i in retval.infer()], + [1.0, 1.0j]) + + def test_lookup_cond_branches(self): + code = ''' + def no_conjugate_member(magic_flag): + """should not raise E1101 on something.conjugate""" + something = 1.0 + if magic_flag: + something = 1.0j + return something.conjugate() + ''' + ast = test_utils.build_module(code, __name__) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'something', -1).infer()], [1.0, 1.0j]) + + + def test_simple_subscript(self): + code = ''' + a = [1, 2, 3][0] + b = (1, 2, 3)[1] + c = (1, 2, 3)[-1] + d = a + b + c + print (d) + e = {'key': 'value'} + f = e['key'] + print (f) + ''' + ast = test_utils.build_module(code, __name__) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'a', -1).infer()], [1]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'b', -1).infer()], [2]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'c', -1).infer()], [3]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'd', -1).infer()], [6]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'f', -1).infer()], ['value']) + + #def test_simple_tuple(self): + #"""test case for a simple tuple value""" + ## XXX tuple inference is not implemented ... + #code = """ +#a = (1,) +#b = (22,) +#some = a + b +#""" + #ast = builder.string_build(code, __name__, __file__) + #self.assertEqual(ast['some'].infer.next().as_string(), "(1, 22)") + + def test_simple_for(self): + code = ''' + for a in [1, 2, 3]: + print (a) + for b,c in [(1,2), (3,4)]: + print (b) + print (c) + + print ([(d,e) for e,d in ([1,2], [3,4])]) + ''' + ast = test_utils.build_module(code, __name__) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'a', -1).infer()], [1, 2, 3]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'b', -1).infer()], [1, 3]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'c', -1).infer()], [2, 4]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'd', -1).infer()], [2, 4]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'e', -1).infer()], [1, 3]) + + + def test_simple_for_genexpr(self): + code = ''' + print ((d,e) for e,d in ([1,2], [3,4])) + ''' + ast = test_utils.build_module(code, __name__) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'd', -1).infer()], [2, 4]) + self.assertEqual([i.value for i in + test_utils.get_name_node(ast, 'e', -1).infer()], [1, 3]) + + + def test_builtin_help(self): + code = ''' + help() + ''' + # XXX failing since __builtin__.help assignment has + # been moved into a function... + node = test_utils.extract_node(code, __name__) + infered = list(node.func.infer()) + self.assertEqual(len(infered), 1, infered) + self.assertIsInstance(infered[0], Instance) + self.assertEqual(infered[0].name, "_Helper") + + def test_builtin_open(self): + code = ''' + open("toto.txt") + ''' + node = test_utils.extract_node(code, __name__).func + infered = list(node.infer()) + self.assertEqual(len(infered), 1) + if hasattr(sys, 'pypy_version_info'): + self.assertIsInstance(infered[0], nodes.Class) + self.assertEqual(infered[0].name, 'file') + else: + self.assertIsInstance(infered[0], nodes.Function) + self.assertEqual(infered[0].name, 'open') + + def test_callfunc_context_func(self): + code = ''' + def mirror(arg=None): + return arg + + un = mirror(1) + ''' + ast = test_utils.build_module(code, __name__) + infered = list(ast.igetattr('un')) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Const) + self.assertEqual(infered[0].value, 1) + + def test_callfunc_context_lambda(self): + code = ''' + mirror = lambda x=None: x + + un = mirror(1) + ''' + ast = test_utils.build_module(code, __name__) + infered = list(ast.igetattr('mirror')) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Lambda) + infered = list(ast.igetattr('un')) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Const) + self.assertEqual(infered[0].value, 1) + + def test_factory_method(self): + code = ''' + class Super(object): + @classmethod + def instance(cls): + return cls() + + class Sub(Super): + def method(self): + print ('method called') + + sub = Sub.instance() + ''' + ast = test_utils.build_module(code, __name__) + infered = list(ast.igetattr('sub')) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], Instance) + self.assertEqual(infered[0]._proxied.name, 'Sub') + + + def test_import_as(self): + code = ''' + import os.path as osp + print (osp.dirname(__file__)) + + from os.path import exists as e + assert e(__file__) + + from new import code as make_code + print (make_code) + ''' + ast = test_utils.build_module(code, __name__) + infered = list(ast.igetattr('osp')) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Module) + self.assertEqual(infered[0].name, 'os.path') + infered = list(ast.igetattr('e')) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Function) + self.assertEqual(infered[0].name, 'exists') + if sys.version_info >= (3, 0): + self.skipTest(' module has been removed') + infered = list(ast.igetattr('make_code')) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], Instance) + self.assertEqual(str(infered[0]), + 'Instance of %s.type' % BUILTINS) + + def _test_const_infered(self, node, value): + infered = list(node.infer()) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Const) + self.assertEqual(infered[0].value, value) + + def test_unary_not(self): + for code in ('a = not (1,); b = not ()', + 'a = not {1:2}; b = not {}'): + ast = builder.string_build(code, __name__, __file__) + self._test_const_infered(ast['a'], False) + self._test_const_infered(ast['b'], True) + + def test_binary_op_int_add(self): + ast = builder.string_build('a = 1 + 2', __name__, __file__) + self._test_const_infered(ast['a'], 3) + + def test_binary_op_int_sub(self): + ast = builder.string_build('a = 1 - 2', __name__, __file__) + self._test_const_infered(ast['a'], -1) + + def test_binary_op_float_div(self): + ast = builder.string_build('a = 1 / 2.', __name__, __file__) + self._test_const_infered(ast['a'], 1 / 2.) + + def test_binary_op_str_mul(self): + ast = builder.string_build('a = "*" * 40', __name__, __file__) + self._test_const_infered(ast['a'], "*" * 40) + + def test_binary_op_bitand(self): + ast = builder.string_build('a = 23&20', __name__, __file__) + self._test_const_infered(ast['a'], 23&20) + + def test_binary_op_bitor(self): + ast = builder.string_build('a = 23|8', __name__, __file__) + self._test_const_infered(ast['a'], 23|8) + + def test_binary_op_bitxor(self): + ast = builder.string_build('a = 23^9', __name__, __file__) + self._test_const_infered(ast['a'], 23^9) + + def test_binary_op_shiftright(self): + ast = builder.string_build('a = 23 >>1', __name__, __file__) + self._test_const_infered(ast['a'], 23>>1) + + def test_binary_op_shiftleft(self): + ast = builder.string_build('a = 23 <<1', __name__, __file__) + self._test_const_infered(ast['a'], 23<<1) + + + def test_binary_op_list_mul(self): + for code in ('a = [[]] * 2', 'a = 2 * [[]]'): + ast = builder.string_build(code, __name__, __file__) + infered = list(ast['a'].infer()) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.List) + self.assertEqual(len(infered[0].elts), 2) + self.assertIsInstance(infered[0].elts[0], nodes.List) + self.assertIsInstance(infered[0].elts[1], nodes.List) + + def test_binary_op_list_mul_none(self): + 'test correct handling on list multiplied by None' + ast = builder.string_build('a = [1] * None\nb = [1] * "r"') + infered = ast['a'].infered() + self.assertEqual(len(infered), 1) + self.assertEqual(infered[0], YES) + infered = ast['b'].infered() + self.assertEqual(len(infered), 1) + self.assertEqual(infered[0], YES) + + + def test_binary_op_tuple_add(self): + ast = builder.string_build('a = (1,) + (2,)', __name__, __file__) + infered = list(ast['a'].infer()) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Tuple) + self.assertEqual(len(infered[0].elts), 2) + self.assertEqual(infered[0].elts[0].value, 1) + self.assertEqual(infered[0].elts[1].value, 2) + + def test_binary_op_custom_class(self): + code = ''' + class myarray: + def __init__(self, array): + self.array = array + def __mul__(self, x): + return myarray([2,4,6]) + def astype(self): + return "ASTYPE" + + def randint(maximum): + if maximum is not None: + return myarray([1,2,3]) * 2 + else: + return int(5) + + x = randint(1) + ''' + ast = test_utils.build_module(code, __name__) + infered = list(ast.igetattr('x')) + self.assertEqual(len(infered), 2) + value = [str(v) for v in infered] + # The __name__ trick here makes it work when invoked directly + # (__name__ == '__main__') and through pytest (__name__ == + # 'unittest_inference') + self.assertEqual(value, ['Instance of %s.myarray' % __name__, + 'Instance of %s.int' % BUILTINS]) + + def test_nonregr_lambda_arg(self): + code = ''' + def f(g = lambda: None): + __(g()).x +''' + callfuncnode = test_utils.extract_node(code) + infered = list(callfuncnode.infer()) + self.assertEqual(len(infered), 2, infered) + infered.remove(YES) + self.assertIsInstance(infered[0], nodes.Const) + self.assertIsNone(infered[0].value) + + def test_nonregr_getitem_empty_tuple(self): + code = ''' + def f(x): + a = ()[x] + ''' + ast = test_utils.build_module(code, __name__) + infered = list(ast['f'].ilookup('a')) + self.assertEqual(len(infered), 1) + self.assertEqual(infered[0], YES) + + def test_nonregr_instance_attrs(self): + """non regression for instance_attrs infinite loop : pylint / #4""" + + code = """ + class Foo(object): + + def set_42(self): + self.attr = 42 + + class Bar(Foo): + + def __init__(self): + self.attr = 41 + """ + ast = test_utils.build_module(code, __name__) + foo_class = ast['Foo'] + bar_class = ast['Bar'] + bar_self = ast['Bar']['__init__']['self'] + assattr = bar_class.instance_attrs['attr'][0] + self.assertEqual(len(foo_class.instance_attrs['attr']), 1) + self.assertEqual(len(bar_class.instance_attrs['attr']), 1) + self.assertEqual(bar_class.instance_attrs, {'attr': [assattr]}) + # call 'instance_attr' via 'Instance.getattr' to trigger the bug: + instance = bar_self.infered()[0] + instance.getattr('attr') + self.assertEqual(len(bar_class.instance_attrs['attr']), 1) + self.assertEqual(len(foo_class.instance_attrs['attr']), 1) + self.assertEqual(bar_class.instance_attrs, {'attr': [assattr]}) + + def test_python25_generator_exit(self): + sys.stderr = six.StringIO() + data = "b = {}[str(0)+''].a" + ast = builder.string_build(data, __name__, __file__) + list(ast['b'].infer()) + output = sys.stderr.getvalue() + # I have no idea how to test for this in another way... + self.assertNotIn("RuntimeError", output, "Exception exceptions.RuntimeError: 'generator ignored GeneratorExit' in ignored") + sys.stderr = sys.__stderr__ + + def test_python25_relative_import(self): + data = "from ...logilab.common import date; print (date)" + # !! FIXME also this relative import would not work 'in real' (no __init__.py in test/) + # the test works since we pretend we have a package by passing the full modname + ast = builder.string_build(data, 'astroid.test.unittest_inference', __file__) + infered = next(test_utils.get_name_node(ast, 'date').infer()) + self.assertIsInstance(infered, nodes.Module) + self.assertEqual(infered.name, 'logilab.common.date') + + def test_python25_no_relative_import(self): + ast = resources.build_file('data/package/absimport.py') + self.assertTrue(ast.absolute_import_activated(), True) + infered = next(test_utils.get_name_node(ast, 'import_package_subpackage_module').infer()) + # failed to import since absolute_import is activated + self.assertIs(infered, YES) + + def test_nonregr_absolute_import(self): + ast = resources.build_file('data/absimp/string.py', 'data.absimp.string') + self.assertTrue(ast.absolute_import_activated(), True) + infered = next(test_utils.get_name_node(ast, 'string').infer()) + self.assertIsInstance(infered, nodes.Module) + self.assertEqual(infered.name, 'string') + self.assertIn('ascii_letters', infered.locals) + + def test_mechanize_open(self): + try: + import mechanize # pylint: disable=unused-variable + except ImportError: + self.skipTest('require mechanize installed') + data = ''' + from mechanize import Browser + print(Browser) + b = Browser() + ''' + ast = test_utils.build_module(data, __name__) + browser = next(test_utils.get_name_node(ast, 'Browser').infer()) + self.assertIsInstance(browser, nodes.Class) + bopen = list(browser.igetattr('open')) + self.skipTest('the commit said: "huum, see that later"') + self.assertEqual(len(bopen), 1) + self.assertIsInstance(bopen[0], nodes.Function) + self.assertTrue(bopen[0].callable()) + b = next(test_utils.get_name_node(ast, 'b').infer()) + self.assertIsInstance(b, Instance) + bopen = list(b.igetattr('open')) + self.assertEqual(len(bopen), 1) + self.assertIsInstance(bopen[0], BoundMethod) + self.assertTrue(bopen[0].callable()) + + def test_property(self): + code = ''' + from smtplib import SMTP + class SendMailController(object): + + @property + def smtp(self): + return SMTP(mailhost, port) + + @property + def me(self): + return self + + my_smtp = SendMailController().smtp + my_me = SendMailController().me + ''' + decorators = set(['%s.property' % BUILTINS]) + ast = test_utils.build_module(code, __name__) + self.assertEqual(ast['SendMailController']['smtp'].decoratornames(), + decorators) + propinfered = list(ast.body[2].value.infer()) + self.assertEqual(len(propinfered), 1) + propinfered = propinfered[0] + self.assertIsInstance(propinfered, Instance) + self.assertEqual(propinfered.name, 'SMTP') + self.assertEqual(propinfered.root().name, 'smtplib') + self.assertEqual(ast['SendMailController']['me'].decoratornames(), + decorators) + propinfered = list(ast.body[3].value.infer()) + self.assertEqual(len(propinfered), 1) + propinfered = propinfered[0] + self.assertIsInstance(propinfered, Instance) + self.assertEqual(propinfered.name, 'SendMailController') + self.assertEqual(propinfered.root().name, __name__) + + + def test_im_func_unwrap(self): + code = ''' + class EnvBasedTC: + def pactions(self): + pass + pactions = EnvBasedTC.pactions.im_func + print (pactions) + + class EnvBasedTC2: + pactions = EnvBasedTC.pactions.im_func + print (pactions) + ''' + ast = test_utils.build_module(code, __name__) + pactions = test_utils.get_name_node(ast, 'pactions') + infered = list(pactions.infer()) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Function) + pactions = test_utils.get_name_node(ast['EnvBasedTC2'], 'pactions') + infered = list(pactions.infer()) + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Function) + + def test_augassign(self): + code = ''' + a = 1 + a += 2 + print (a) + ''' + ast = test_utils.build_module(code, __name__) + infered = list(test_utils.get_name_node(ast, 'a').infer()) + + self.assertEqual(len(infered), 1) + self.assertIsInstance(infered[0], nodes.Const) + self.assertEqual(infered[0].value, 3) + + def test_nonregr_func_arg(self): + code = ''' + def foo(self, bar): + def baz(): + pass + def qux(): + return baz + spam = bar(None, qux) + print (spam) + ''' + ast = test_utils.build_module(code, __name__) + infered = list(test_utils.get_name_node(ast['foo'], 'spam').infer()) + self.assertEqual(len(infered), 1) + self.assertIs(infered[0], YES) + + def test_nonregr_func_global(self): + code = ''' + active_application = None + + def get_active_application(): + global active_application + return active_application + + class Application(object): + def __init__(self): + global active_application + active_application = self + + class DataManager(object): + def __init__(self, app=None): + self.app = get_active_application() + def test(self): + p = self.app + print (p) + ''' + ast = test_utils.build_module(code, __name__) + infered = list(Instance(ast['DataManager']).igetattr('app')) + self.assertEqual(len(infered), 2, infered) # None / Instance(Application) + infered = list(test_utils.get_name_node(ast['DataManager']['test'], 'p').infer()) + self.assertEqual(len(infered), 2, infered) + for node in infered: + if isinstance(node, Instance) and node.name == 'Application': + break + else: + self.fail('expected to find an instance of Application in %s' % infered) + + def test_list_inference(self): + """#20464""" + code = ''' + import optparse + + A = [] + B = [] + + def test(): + xyz = [ + "foobar=%s" % options.ca, + ] + A + B + + if options.bind is not None: + xyz.append("bind=%s" % options.bind) + return xyz + + def main(): + global options + + parser = optparse.OptionParser() + (options, args) = parser.parse_args() + + Z = test() + ''' + ast = test_utils.build_module(code, __name__) + infered = list(ast['Z'].infer()) + self.assertEqual(len(infered), 1, infered) + self.assertIsInstance(infered[0], Instance) + self.assertIsInstance(infered[0]._proxied, nodes.Class) + self.assertEqual(infered[0]._proxied.name, 'list') + + def test__new__(self): + code = ''' + class NewTest(object): + "doc" + def __new__(cls, arg): + self = object.__new__(cls) + self.arg = arg + return self + + n = NewTest() + ''' + ast = test_utils.build_module(code, __name__) + self.assertRaises(InferenceError, list, ast['NewTest'].igetattr('arg')) + n = next(ast['n'].infer()) + infered = list(n.igetattr('arg')) + self.assertEqual(len(infered), 1, infered) + + + def test_two_parents_from_same_module(self): + code = ''' + from data import nonregr + class Xxx(nonregr.Aaa, nonregr.Ccc): + "doc" + ''' + ast = test_utils.build_module(code, __name__) + parents = list(ast['Xxx'].ancestors()) + self.assertEqual(len(parents), 3, parents) # Aaa, Ccc, object + + def test_pluggable_inference(self): + code = ''' + from collections import namedtuple + A = namedtuple('A', ['a', 'b']) + B = namedtuple('B', 'a b') + ''' + ast = test_utils.build_module(code, __name__) + aclass = ast['A'].infered()[0] + self.assertIsInstance(aclass, nodes.Class) + self.assertIn('a', aclass.instance_attrs) + self.assertIn('b', aclass.instance_attrs) + bclass = ast['B'].infered()[0] + self.assertIsInstance(bclass, nodes.Class) + self.assertIn('a', bclass.instance_attrs) + self.assertIn('b', bclass.instance_attrs) + + def test_infer_arguments(self): + code = ''' + class A(object): + def first(self, arg1, arg2): + return arg1 + @classmethod + def method(cls, arg1, arg2): + return arg2 + @classmethod + def empty(cls): + return 2 + @staticmethod + def static(arg1, arg2): + return arg1 + def empty_method(self): + return [] + x = A().first(1, []) + y = A.method(1, []) + z = A.static(1, []) + empty = A.empty() + empty_list = A().empty_method() + ''' + ast = test_utils.build_module(code, __name__) + int_node = ast['x'].infered()[0] + self.assertIsInstance(int_node, nodes.Const) + self.assertEqual(int_node.value, 1) + list_node = ast['y'].infered()[0] + self.assertIsInstance(list_node, nodes.List) + int_node = ast['z'].infered()[0] + self.assertIsInstance(int_node, nodes.Const) + self.assertEqual(int_node.value, 1) + empty = ast['empty'].infered()[0] + self.assertIsInstance(empty, nodes.Const) + self.assertEqual(empty.value, 2) + empty_list = ast['empty_list'].infered()[0] + self.assertIsInstance(empty_list, nodes.List) + + def test_infer_variable_arguments(self): + code = ''' + def test(*args, **kwargs): + vararg = args + kwarg = kwargs + ''' + ast = test_utils.build_module(code, __name__) + func = ast['test'] + vararg = func.body[0].value + kwarg = func.body[1].value + + kwarg_infered = kwarg.infered()[0] + self.assertIsInstance(kwarg_infered, nodes.Dict) + self.assertIs(kwarg_infered.parent, func.args) + + vararg_infered = vararg.infered()[0] + self.assertIsInstance(vararg_infered, nodes.Tuple) + self.assertIs(vararg_infered.parent, func.args) + + def test_infer_nested(self): + code = """ + def nested(): + from threading import Thread + + class NestedThread(Thread): + def __init__(self): + Thread.__init__(self) + """ + # Test that inferring Thread.__init__ looks up in + # the nested scope. + ast = test_utils.build_module(code, __name__) + callfunc = next(ast.nodes_of_class(nodes.CallFunc)) + func = callfunc.func + infered = func.infered()[0] + self.assertIsInstance(infered, UnboundMethod) + + def test_instance_binary_operations(self): + code = """ + class A(object): + def __mul__(self, other): + return 42 + a = A() + b = A() + sub = a - b + mul = a * b + """ + ast = test_utils.build_module(code, __name__) + sub = ast['sub'].infered()[0] + mul = ast['mul'].infered()[0] + self.assertIs(sub, YES) + self.assertIsInstance(mul, nodes.Const) + self.assertEqual(mul.value, 42) + + def test_instance_binary_operations_parent(self): + code = """ + class A(object): + def __mul__(self, other): + return 42 + class B(A): + pass + a = B() + b = B() + sub = a - b + mul = a * b + """ + ast = test_utils.build_module(code, __name__) + sub = ast['sub'].infered()[0] + mul = ast['mul'].infered()[0] + self.assertIs(sub, YES) + self.assertIsInstance(mul, nodes.Const) + self.assertEqual(mul.value, 42) + + def test_instance_binary_operations_multiple_methods(self): + code = """ + class A(object): + def __mul__(self, other): + return 42 + class B(A): + def __mul__(self, other): + return [42] + a = B() + b = B() + sub = a - b + mul = a * b + """ + ast = test_utils.build_module(code, __name__) + sub = ast['sub'].infered()[0] + mul = ast['mul'].infered()[0] + self.assertIs(sub, YES) + self.assertIsInstance(mul, nodes.List) + self.assertIsInstance(mul.elts[0], nodes.Const) + self.assertEqual(mul.elts[0].value, 42) + + def test_infer_call_result_crash(self): + code = """ + class A(object): + def __mul__(self, other): + return type.__new__() + + a = A() + b = A() + c = a * b + """ + ast = test_utils.build_module(code, __name__) + node = ast['c'] + self.assertEqual(node.infered(), [YES]) + + def test_infer_empty_nodes(self): + # Should not crash when trying to infer EmptyNodes. + node = nodes.EmptyNode() + self.assertEqual(node.infered(), [YES]) + + def test_infinite_loop_for_decorators(self): + # Issue https://bitbucket.org/logilab/astroid/issue/50 + # A decorator that returns itself leads to an infinite loop. + code = """ + def decorator(): + def wrapper(): + return decorator() + return wrapper + + @decorator() + def do_a_thing(): + pass + """ + ast = test_utils.build_module(code, __name__) + node = ast['do_a_thing'] + self.assertEqual(node.type, 'function') + + def test_no_infinite_ancestor_loop(self): + klass = test_utils.extract_node(""" + import datetime + + def method(self): + datetime.datetime = something() + + class something(datetime.datetime): #@ + pass + """) + self.assertIn( + 'object', + [base.name for base in klass.ancestors()]) + + def test_stop_iteration_leak(self): + code = """ + class Test: + def __init__(self): + self.config = {0: self.config[0]} + self.config[0].test() #@ + """ + ast = test_utils.extract_node(code, __name__) + expr = ast.func.expr + self.assertRaises(InferenceError, next, expr.infer()) + + def test_tuple_builtin_inference(self): + code = """ + var = (1, 2) + tuple() #@ + tuple([1]) #@ + tuple({2}) #@ + tuple("abc") #@ + tuple({1: 2}) #@ + tuple(var) #@ + tuple(tuple([1])) #@ + + tuple(None) #@ + tuple(1) #@ + tuple(1, 2) #@ + """ + ast = test_utils.extract_node(code, __name__) + + self.assertInferTuple(ast[0], []) + self.assertInferTuple(ast[1], [1]) + self.assertInferTuple(ast[2], [2]) + self.assertInferTuple(ast[3], ["a", "b", "c"]) + self.assertInferTuple(ast[4], [1]) + self.assertInferTuple(ast[5], [1, 2]) + self.assertInferTuple(ast[6], [1]) + + for node in ast[7:]: + infered = next(node.infer()) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.qname(), "{}.tuple".format(BUILTINS)) + + def test_set_builtin_inference(self): + code = """ + var = (1, 2) + set() #@ + set([1, 2, 1]) #@ + set({2, 3, 1}) #@ + set("abcab") #@ + set({1: 2}) #@ + set(var) #@ + set(tuple([1])) #@ + + set(set(tuple([4, 5, set([2])]))) #@ + set(None) #@ + set(1) #@ + set(1, 2) #@ + """ + ast = test_utils.extract_node(code, __name__) + + self.assertInferSet(ast[0], []) + self.assertInferSet(ast[1], [1, 2]) + self.assertInferSet(ast[2], [1, 2, 3]) + self.assertInferSet(ast[3], ["a", "b", "c"]) + self.assertInferSet(ast[4], [1]) + self.assertInferSet(ast[5], [1, 2]) + self.assertInferSet(ast[6], [1]) + + for node in ast[7:]: + infered = next(node.infer()) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.qname(), "{}.set".format(BUILTINS)) + + def test_list_builtin_inference(self): + code = """ + var = (1, 2) + list() #@ + list([1, 2, 1]) #@ + list({2, 3, 1}) #@ + list("abcab") #@ + list({1: 2}) #@ + list(var) #@ + list(tuple([1])) #@ + + list(list(tuple([4, 5, list([2])]))) #@ + list(None) #@ + list(1) #@ + list(1, 2) #@ + """ + ast = test_utils.extract_node(code, __name__) + self.assertInferList(ast[0], []) + self.assertInferList(ast[1], [1, 1, 2]) + self.assertInferList(ast[2], [1, 2, 3]) + self.assertInferList(ast[3], ["a", "a", "b", "b", "c"]) + self.assertInferList(ast[4], [1]) + self.assertInferList(ast[5], [1, 2]) + self.assertInferList(ast[6], [1]) + + for node in ast[7:]: + infered = next(node.infer()) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.qname(), "{}.list".format(BUILTINS)) + + @test_utils.require_version('3.0') + def test_builtin_inference_py3k(self): + code = """ + list(b"abc") #@ + tuple(b"abc") #@ + set(b"abc") #@ + """ + ast = test_utils.extract_node(code, __name__) + self.assertInferList(ast[0], [97, 98, 99]) + self.assertInferTuple(ast[1], [97, 98, 99]) + self.assertInferSet(ast[2], [97, 98, 99]) + + def test_dict_inference(self): + code = """ + dict() #@ + dict(a=1, b=2, c=3) #@ + dict([(1, 2), (2, 3)]) #@ + dict([[1, 2], [2, 3]]) #@ + dict([(1, 2), [2, 3]]) #@ + dict([('a', 2)], b=2, c=3) #@ + dict({1: 2}) #@ + dict({'c': 2}, a=4, b=5) #@ + def func(): + return dict(a=1, b=2) + func() #@ + var = {'x': 2, 'y': 3} + dict(var, a=1, b=2) #@ + + dict([1, 2, 3]) #@ + dict([(1, 2), (1, 2, 3)]) #@ + dict({1: 2}, {1: 2}) #@ + dict({1: 2}, (1, 2)) #@ + dict({1: 2}, (1, 2), a=4) #@ + dict([(1, 2), ([4, 5], 2)]) #@ + dict([None, None]) #@ + + def using_unknown_kwargs(**kwargs): + return dict(**kwargs) + using_unknown_kwargs(a=1, b=2) #@ + """ + ast = test_utils.extract_node(code, __name__) + self.assertInferDict(ast[0], {}) + self.assertInferDict(ast[1], {'a': 1, 'b': 2, 'c': 3}) + for i in range(2, 5): + self.assertInferDict(ast[i], {1: 2, 2: 3}) + self.assertInferDict(ast[5], {'a': 2, 'b': 2, 'c': 3}) + self.assertInferDict(ast[6], {1: 2}) + self.assertInferDict(ast[7], {'c': 2, 'a': 4, 'b': 5}) + self.assertInferDict(ast[8], {'a': 1, 'b': 2}) + self.assertInferDict(ast[9], {'x': 2, 'y': 3, 'a': 1, 'b': 2}) + + for node in ast[10:]: + infered = next(node.infer()) + self.assertIsInstance(infered, Instance) + self.assertEqual(infered.qname(), "{}.dict".format(BUILTINS)) + + + def test_str_methods(self): + code = """ + ' '.decode() #@ + + ' '.encode() #@ + ' '.join('abcd') #@ + ' '.replace('a', 'b') #@ + ' '.format('a') #@ + ' '.capitalize() #@ + ' '.title() #@ + ' '.lower() #@ + ' '.upper() #@ + ' '.swapcase() #@ + ' '.strip() #@ + ' '.rstrip() #@ + ' '.lstrip() #@ + ' '.rjust() #@ + ' '.ljust() #@ + ' '.center() #@ + + ' '.index() #@ + ' '.find() #@ + ' '.count() #@ + """ + ast = test_utils.extract_node(code, __name__) + self.assertInferConst(ast[0], u'') + for i in range(1, 16): + self.assertInferConst(ast[i], '') + for i in range(16, 19): + self.assertInferConst(ast[i], 0) + + def test_unicode_methods(self): + code = """ + u' '.encode() #@ + + u' '.decode() #@ + u' '.join('abcd') #@ + u' '.replace('a', 'b') #@ + u' '.format('a') #@ + u' '.capitalize() #@ + u' '.title() #@ + u' '.lower() #@ + u' '.upper() #@ + u' '.swapcase() #@ + u' '.strip() #@ + u' '.rstrip() #@ + u' '.lstrip() #@ + u' '.rjust() #@ + u' '.ljust() #@ + u' '.center() #@ + + u' '.index() #@ + u' '.find() #@ + u' '.count() #@ + """ + ast = test_utils.extract_node(code, __name__) + self.assertInferConst(ast[0], '') + for i in range(1, 16): + self.assertInferConst(ast[i], u'') + for i in range(16, 19): + self.assertInferConst(ast[i], 0) + + def test_scope_lookup_same_attributes(self): + code = ''' + import collections + class Second(collections.Counter): + def collections(self): + return "second" + + ''' + ast = test_utils.build_module(code, __name__) + bases = ast['Second'].bases[0] + inferred = next(bases.infer()) + self.assertTrue(inferred) + self.assertIsInstance(inferred, nodes.Class) + self.assertEqual(inferred.qname(), 'collections.Counter') + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_inspector.py astroid-1.3.8/astroid/tests/unittest_inspector.py --- astroid-1.0.1/astroid/tests/unittest_inspector.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_inspector.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,94 @@ +# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" + for the visitors.diadefs module +""" + +import unittest + + +from astroid import nodes, inspector +from astroid.bases import Instance, YES +from astroid.manager import AstroidManager, _silent_no_wrap +from astroid.tests import resources + +MANAGER = AstroidManager() + +def astroid_wrapper(func, modname): + return func(modname) + + +class LinkerTest(resources.SysPathSetup, unittest.TestCase): + + def setUp(self): + super(LinkerTest, self).setUp() + self.project = MANAGER.project_from_files( + [resources.find('data')], + astroid_wrapper, + black_list=['joined_strings.py']) + self.linker = inspector.Linker(self.project) + self.linker.visit(self.project) + + def test_class_implements(self): + klass = self.project.get_module('data.clientmodule_test')['Ancestor'] + self.assertTrue(hasattr(klass, 'implements')) + self.assertEqual(len(klass.implements), 1) + self.assertTrue(isinstance(klass.implements[0], nodes.Class)) + self.assertEqual(klass.implements[0].name, "Interface") + klass = self.project.get_module('data.clientmodule_test')['Specialization'] + self.assertTrue(hasattr(klass, 'implements')) + self.assertEqual(len(klass.implements), 0) + + def test_locals_assignment_resolution(self): + klass = self.project.get_module('data.clientmodule_test')['Specialization'] + self.assertTrue(hasattr(klass, 'locals_type')) + type_dict = klass.locals_type + self.assertEqual(len(type_dict), 2) + keys = sorted(type_dict.keys()) + self.assertEqual(keys, ['TYPE', 'top']) + self.assertEqual(len(type_dict['TYPE']), 1) + self.assertEqual(type_dict['TYPE'][0].value, 'final class') + self.assertEqual(len(type_dict['top']), 1) + self.assertEqual(type_dict['top'][0].value, 'class') + + def test_instance_attrs_resolution(self): + klass = self.project.get_module('data.clientmodule_test')['Specialization'] + self.assertTrue(hasattr(klass, 'instance_attrs_type')) + type_dict = klass.instance_attrs_type + self.assertEqual(len(type_dict), 3) + keys = sorted(type_dict.keys()) + self.assertEqual(keys, ['_id', 'relation', 'toto']) + self.assertTrue(isinstance(type_dict['relation'][0], Instance), type_dict['relation']) + self.assertEqual(type_dict['relation'][0].name, 'DoNothing') + self.assertTrue(isinstance(type_dict['toto'][0], Instance), type_dict['toto']) + self.assertEqual(type_dict['toto'][0].name, 'Toto') + self.assertIs(type_dict['_id'][0], YES) + + +class LinkerTest2(LinkerTest): + + def setUp(self): + resources.SysPathSetup.setUp(self) + self.project = MANAGER.project_from_files( + [resources.find('data')], + func_wrapper=_silent_no_wrap, + black_list=['joined_strings.py']) + self.linker = inspector.Linker(self.project) + self.linker.visit(self.project) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_lookup.py astroid-1.3.8/astroid/tests/unittest_lookup.py --- astroid-1.0.1/astroid/tests/unittest_lookup.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_lookup.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,354 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""tests for the astroid variable lookup capabilities +""" +import sys +from functools import partial +import unittest + +from astroid import nodes, InferenceError, NotFoundError, UnresolvableName +from astroid.scoped_nodes import builtin_lookup +from astroid.bases import YES +from astroid import test_utils +from astroid.tests import resources + + +class LookupTest(resources.SysPathSetup, unittest.TestCase): + + def setUp(self): + super(LookupTest, self).setUp() + self.module = resources.build_file('data/module.py', 'data.module') + self.module2 = resources.build_file('data/module2.py', 'data.module2') + self.nonregr = resources.build_file('data/nonregr.py', 'data.nonregr') + + def test_limit(self): + code = ''' + l = [a + for a,b in list] + + a = 1 + b = a + a = None + + def func(): + c = 1 + ''' + astroid = test_utils.build_module(code, __name__) + # a & b + a = next(astroid.nodes_of_class(nodes.Name)) + self.assertEqual(a.lineno, 2) + if sys.version_info < (3, 0): + self.assertEqual(len(astroid.lookup('b')[1]), 2) + self.assertEqual(len(astroid.lookup('a')[1]), 3) + b = astroid.locals['b'][1] + else: + self.assertEqual(len(astroid.lookup('b')[1]), 1) + self.assertEqual(len(astroid.lookup('a')[1]), 2) + b = astroid.locals['b'][0] + stmts = a.lookup('a')[1] + self.assertEqual(len(stmts), 1) + self.assertEqual(b.lineno, 6) + b_infer = b.infer() + b_value = next(b_infer) + self.assertEqual(b_value.value, 1) + # c + self.assertRaises(StopIteration, partial(next, b_infer)) + func = astroid.locals['func'][0] + self.assertEqual(len(func.lookup('c')[1]), 1) + + def test_module(self): + astroid = test_utils.build_module('pass', __name__) + # built-in objects + none = next(astroid.ilookup('None')) + self.assertIsNone(none.value) + obj = next(astroid.ilookup('object')) + self.assertIsInstance(obj, nodes.Class) + self.assertEqual(obj.name, 'object') + self.assertRaises(InferenceError, partial(next, astroid.ilookup('YOAA'))) + + # XXX + self.assertEqual(len(list(self.nonregr.ilookup('enumerate'))), 2) + + def test_class_ancestor_name(self): + code = ''' + class A: + pass + + class A(A): + pass + ''' + astroid = test_utils.build_module(code, __name__) + cls1 = astroid.locals['A'][0] + cls2 = astroid.locals['A'][1] + name = next(cls2.nodes_of_class(nodes.Name)) + self.assertEqual(next(name.infer()), cls1) + + ### backport those test to inline code + def test_method(self): + method = self.module['YOUPI']['method'] + my_dict = next(method.ilookup('MY_DICT')) + self.assertTrue(isinstance(my_dict, nodes.Dict), my_dict) + none = next(method.ilookup('None')) + self.assertIsNone(none.value) + self.assertRaises(InferenceError, partial(next, method.ilookup('YOAA'))) + + + def test_function_argument_with_default(self): + make_class = self.module2['make_class'] + base = next(make_class.ilookup('base')) + self.assertTrue(isinstance(base, nodes.Class), base.__class__) + self.assertEqual(base.name, 'YO') + self.assertEqual(base.root().name, 'data.module') + + def test_class(self): + klass = self.module['YOUPI'] + my_dict = next(klass.ilookup('MY_DICT')) + self.assertIsInstance(my_dict, nodes.Dict) + none = next(klass.ilookup('None')) + self.assertIsNone(none.value) + obj = next(klass.ilookup('object')) + self.assertIsInstance(obj, nodes.Class) + self.assertEqual(obj.name, 'object') + self.assertRaises(InferenceError, partial(next, klass.ilookup('YOAA'))) + + def test_inner_classes(self): + ddd = list(self.nonregr['Ccc'].ilookup('Ddd')) + self.assertEqual(ddd[0].name, 'Ddd') + + + def test_loopvar_hiding(self): + astroid = test_utils.build_module(""" + x = 10 + for x in range(5): + print (x) + + if x > 0: + print ('#' * x) + """, __name__) + xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'x'] + # inside the loop, only one possible assignment + self.assertEqual(len(xnames[0].lookup('x')[1]), 1) + # outside the loop, two possible assignments + self.assertEqual(len(xnames[1].lookup('x')[1]), 2) + self.assertEqual(len(xnames[2].lookup('x')[1]), 2) + + def test_list_comps(self): + astroid = test_utils.build_module(""" + print ([ i for i in range(10) ]) + print ([ i for i in range(10) ]) + print ( list( i for i in range(10) ) ) + """, __name__) + xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'i'] + self.assertEqual(len(xnames[0].lookup('i')[1]), 1) + self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) + self.assertEqual(len(xnames[1].lookup('i')[1]), 1) + self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) + self.assertEqual(len(xnames[2].lookup('i')[1]), 1) + self.assertEqual(xnames[2].lookup('i')[1][0].lineno, 4) + + def test_list_comp_target(self): + """test the list comprehension target""" + astroid = test_utils.build_module(""" + ten = [ var for var in range(10) ] + var + """) + var = astroid.body[1].value + if sys.version_info < (3, 0): + self.assertEqual(var.infered(), [YES]) + else: + self.assertRaises(UnresolvableName, var.infered) + + def test_dict_comps(self): + astroid = test_utils.build_module(""" + print ({ i: j for i in range(10) for j in range(10) }) + print ({ i: j for i in range(10) for j in range(10) }) + """, __name__) + xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'i'] + self.assertEqual(len(xnames[0].lookup('i')[1]), 1) + self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) + self.assertEqual(len(xnames[1].lookup('i')[1]), 1) + self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) + + xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'j'] + self.assertEqual(len(xnames[0].lookup('i')[1]), 1) + self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) + self.assertEqual(len(xnames[1].lookup('i')[1]), 1) + self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) + + def test_set_comps(self): + astroid = test_utils.build_module(""" + print ({ i for i in range(10) }) + print ({ i for i in range(10) }) + """, __name__) + xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'i'] + self.assertEqual(len(xnames[0].lookup('i')[1]), 1) + self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) + self.assertEqual(len(xnames[1].lookup('i')[1]), 1) + self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) + + def test_set_comp_closure(self): + astroid = test_utils.build_module(""" + ten = { var for var in range(10) } + var + """) + var = astroid.body[1].value + self.assertRaises(UnresolvableName, var.infered) + + def test_generator_attributes(self): + tree = test_utils.build_module(""" + def count(): + "test" + yield 0 + + iterer = count() + num = iterer.next() + """) + next = tree.body[2].value.func # Getattr + gener = next.expr.infered()[0] # Generator + if sys.version_info < (3, 0): + self.assertIsInstance(gener.getattr('next')[0], nodes.Function) + else: + self.assertIsInstance(gener.getattr('__next__')[0], nodes.Function) + self.assertIsInstance(gener.getattr('send')[0], nodes.Function) + self.assertIsInstance(gener.getattr('throw')[0], nodes.Function) + self.assertIsInstance(gener.getattr('close')[0], nodes.Function) + + def test_explicit___name__(self): + code = ''' + class Pouet: + __name__ = "pouet" + p1 = Pouet() + + class PouetPouet(Pouet): pass + p2 = Pouet() + + class NoName: pass + p3 = NoName() + ''' + astroid = test_utils.build_module(code, __name__) + p1 = next(astroid['p1'].infer()) + self.assertTrue(p1.getattr('__name__')) + p2 = next(astroid['p2'].infer()) + self.assertTrue(p2.getattr('__name__')) + self.assertTrue(astroid['NoName'].getattr('__name__')) + p3 = next(astroid['p3'].infer()) + self.assertRaises(NotFoundError, p3.getattr, '__name__') + + + def test_function_module_special(self): + astroid = test_utils.build_module(''' + def initialize(linter): + """initialize linter with checkers in this package """ + package_load(linter, __path__[0]) + ''', 'data.__init__') + path = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == '__path__'][0] + self.assertEqual(len(path.lookup('__path__')[1]), 1) + + + def test_builtin_lookup(self): + self.assertEqual(builtin_lookup('__dict__')[1], ()) + intstmts = builtin_lookup('int')[1] + self.assertEqual(len(intstmts), 1) + self.assertIsInstance(intstmts[0], nodes.Class) + self.assertEqual(intstmts[0].name, 'int') + self.assertIs(intstmts[0], nodes.const_factory(1)._proxied) + + + def test_decorator_arguments_lookup(self): + code = ''' + def decorator(value): + def wrapper(function): + return function + return wrapper + + class foo: + member = 10 #@ + + @decorator(member) #This will cause pylint to complain + def test(self): + pass + ''' + member = test_utils.extract_node(code, __name__).targets[0] + it = member.infer() + obj = next(it) + self.assertIsInstance(obj, nodes.Const) + self.assertEqual(obj.value, 10) + self.assertRaises(StopIteration, partial(next, it)) + + + def test_inner_decorator_member_lookup(self): + code = ''' + class FileA: + def decorator(bla): + return bla + + @__(decorator) + def funcA(): + return 4 + ''' + decname = test_utils.extract_node(code, __name__) + it = decname.infer() + obj = next(it) + self.assertIsInstance(obj, nodes.Function) + self.assertRaises(StopIteration, partial(next, it)) + + + def test_static_method_lookup(self): + code = ''' + class FileA: + @staticmethod + def funcA(): + return 4 + + + class Test: + FileA = [1,2,3] + + def __init__(self): + print (FileA.funcA()) + ''' + astroid = test_utils.build_module(code, __name__) + it = astroid['Test']['__init__'].ilookup('FileA') + obj = next(it) + self.assertIsInstance(obj, nodes.Class) + self.assertRaises(StopIteration, partial(next, it)) + + + def test_global_delete(self): + code = ''' + def run2(): + f = Frobble() + + class Frobble: + pass + Frobble.mumble = True + + del Frobble + + def run1(): + f = Frobble() + ''' + astroid = test_utils.build_module(code, __name__) + stmts = astroid['run2'].lookup('Frobbel')[1] + self.assertEqual(len(stmts), 0) + stmts = astroid['run1'].lookup('Frobbel')[1] + self.assertEqual(len(stmts), 0) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_manager.py astroid-1.3.8/astroid/tests/unittest_manager.py --- astroid-1.0.1/astroid/tests/unittest_manager.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_manager.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,263 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +import os +import sys +import unittest + +from astroid.manager import AstroidManager, _silent_no_wrap +from astroid.bases import BUILTINS +from astroid.exceptions import AstroidBuildingException +from astroid.tests import resources + + +class AstroidManagerTest(resources.SysPathSetup, + resources.AstroidCacheSetupMixin, + unittest.TestCase): + + @property + def project(self): + return self.manager.project_from_files( + [resources.find('data')], + _silent_no_wrap, 'data', + black_list=['joined_strings.py']) + + def setUp(self): + super(AstroidManagerTest, self).setUp() + self.manager = AstroidManager() + self.manager.clear_cache(self._builtins) # take care of borg + + def test_ast_from_file(self): + """check if the method return a good astroid object""" + import unittest + filepath = unittest.__file__ + astroid = self.manager.ast_from_file(filepath) + self.assertEqual(astroid.name, 'unittest') + self.assertIn('unittest', self.manager.astroid_cache) + + def test_ast_from_file_cache(self): + """check if the cache works""" + import unittest + filepath = unittest.__file__ + self.manager.ast_from_file(filepath) + astroid = self.manager.ast_from_file('unhandledName', 'unittest') + self.assertEqual(astroid.name, 'unittest') + self.assertIn('unittest', self.manager.astroid_cache) + + def test_ast_from_file_astro_builder(self): + """check if the source is at True, AstroidBuilder build a good astroid""" + import unittest + filepath = unittest.__file__ + astroid = self.manager.ast_from_file(filepath, None, True, True) + self.assertEqual(astroid.name, 'unittest') + self.assertIn('unittest', self.manager.astroid_cache) + + def test_ast_from_file_name_astro_builder_exception(self): + """check if an exception is thrown if we give a wrong filepath""" + self.assertRaises(AstroidBuildingException, self.manager.ast_from_file, 'unhandledName') + + def test_do_not_expose_main(self): + obj = self.manager.ast_from_module_name('__main__') + self.assertEqual(obj.name, '__main__') + self.assertEqual(obj.items(), []) + + def test_ast_from_module_name(self): + """check if the ast_from_module_name method return a good astroid""" + astroid = self.manager.ast_from_module_name('unittest') + self.assertEqual(astroid.name, 'unittest') + self.assertIn('unittest', self.manager.astroid_cache) + + def test_ast_from_module_name_not_python_source(self): + """check if the ast_from_module_name method return a good astroid with a no python source module""" + astroid = self.manager.ast_from_module_name('time') + self.assertEqual(astroid.name, 'time') + self.assertIn('time', self.manager.astroid_cache) + self.assertEqual(astroid.pure_python, False) + + def test_ast_from_module_name_astro_builder_exception(self): + """check if the method raise an exception if we give a wrong module""" + self.assertRaises(AstroidBuildingException, self.manager.ast_from_module_name, 'unhandledModule') + + def _test_ast_from_zip(self, archive): + origpath = sys.path[:] + sys.modules.pop('mypypa', None) + archive_path = resources.find(archive) + sys.path.insert(0, archive_path) + try: + module = self.manager.ast_from_module_name('mypypa') + self.assertEqual(module.name, 'mypypa') + end = os.path.join(archive, 'mypypa') + self.assertTrue(module.file.endswith(end), + "%s doesn't endswith %s" % (module.file, end)) + finally: + # remove the module, else after importing egg, we don't get the zip + if 'mypypa' in self.manager.astroid_cache: + del self.manager.astroid_cache['mypypa'] + del self.manager._mod_file_cache[('mypypa', None)] + if archive_path in sys.path_importer_cache: + del sys.path_importer_cache[archive_path] + sys.path = origpath + + def test_ast_from_module_name_egg(self): + self._test_ast_from_zip( + os.path.sep.join(['data', os.path.normcase('MyPyPa-0.1.0-py2.5.egg')]) + ) + + def test_ast_from_module_name_zip(self): + self._test_ast_from_zip( + os.path.sep.join(['data', os.path.normcase('MyPyPa-0.1.0-py2.5.zip')]) + ) + + def test_zip_import_data(self): + """check if zip_import_data works""" + filepath = resources.find('data/MyPyPa-0.1.0-py2.5.zip/mypypa') + astroid = self.manager.zip_import_data(filepath) + self.assertEqual(astroid.name, 'mypypa') + + def test_zip_import_data_without_zipimport(self): + """check if zip_import_data return None without zipimport""" + self.assertEqual(self.manager.zip_import_data('path'), None) + + def test_file_from_module(self): + """check if the unittest filepath is equals to the result of the method""" + if sys.version_info > (3, 0): + unittest_file = unittest.__file__ + else: + unittest_file = unittest.__file__[:-1] + self.assertEqual(unittest_file, + self.manager.file_from_module_name('unittest', None)[0]) + + def test_file_from_module_name_astro_building_exception(self): + """check if the method launch a exception with a wrong module name""" + self.assertRaises(AstroidBuildingException, self.manager.file_from_module_name, 'unhandledModule', None) + + def test_ast_from_module(self): + astroid = self.manager.ast_from_module(unittest) + self.assertEqual(astroid.pure_python, True) + import time + astroid = self.manager.ast_from_module(time) + self.assertEqual(astroid.pure_python, False) + + def test_ast_from_module_cache(self): + """check if the module is in the cache manager""" + astroid = self.manager.ast_from_module(unittest) + self.assertEqual(astroid.name, 'unittest') + self.assertIn('unittest', self.manager.astroid_cache) + + def test_ast_from_class(self): + astroid = self.manager.ast_from_class(int) + self.assertEqual(astroid.name, 'int') + self.assertEqual(astroid.parent.frame().name, BUILTINS) + + astroid = self.manager.ast_from_class(object) + self.assertEqual(astroid.name, 'object') + self.assertEqual(astroid.parent.frame().name, BUILTINS) + self.assertIn('__setattr__', astroid) + + def test_ast_from_class_with_module(self): + """check if the method works with the module name""" + astroid = self.manager.ast_from_class(int, int.__module__) + self.assertEqual(astroid.name, 'int') + self.assertEqual(astroid.parent.frame().name, BUILTINS) + + astroid = self.manager.ast_from_class(object, object.__module__) + self.assertEqual(astroid.name, 'object') + self.assertEqual(astroid.parent.frame().name, BUILTINS) + self.assertIn('__setattr__', astroid) + + def test_ast_from_class_attr_error(self): + """give a wrong class at the ast_from_class method""" + self.assertRaises(AstroidBuildingException, self.manager.ast_from_class, None) + + def test_from_directory(self): + self.assertEqual(self.project.name, 'data') + self.assertEqual(self.project.path, + os.path.abspath(resources.find('data/__init__.py'))) + + def test_project_node(self): + expected = [ + 'data', + 'data.SSL1', + 'data.SSL1.Connection1', + 'data.absimp', + 'data.absimp.sidepackage', + 'data.absimp.string', + 'data.absimport', + 'data.all', + 'data.appl', + 'data.appl.myConnection', + 'data.clientmodule_test', + 'data.descriptor_crash', + 'data.email', + 'data.find_test', + 'data.find_test.module', + 'data.find_test.module2', + 'data.find_test.noendingnewline', + 'data.find_test.nonregr', + 'data.format', + 'data.lmfp', + 'data.lmfp.foo', + 'data.module', + 'data.module1abs', + 'data.module1abs.core', + 'data.module2', + 'data.noendingnewline', + 'data.nonregr', + 'data.notall', + 'data.package', + 'data.package.absimport', + 'data.package.hello', + 'data.package.import_package_subpackage_module', + 'data.package.subpackage', + 'data.package.subpackage.module', + 'data.recursion', + 'data.suppliermodule_test', + 'data.unicode_package', + 'data.unicode_package.core'] + self.assertListEqual(sorted(self.project.keys()), expected) + + def testFailedImportHooks(self): + def hook(modname): + if modname == 'foo.bar': + return unittest + else: + raise AstroidBuildingException() + + with self.assertRaises(AstroidBuildingException): + self.manager.ast_from_module_name('foo.bar') + self.manager.register_failed_import_hook(hook) + self.assertEqual(unittest, self.manager.ast_from_module_name('foo.bar')) + with self.assertRaises(AstroidBuildingException): + self.manager.ast_from_module_name('foo.bar.baz') + del self.manager._failed_import_hooks[0] + + +class BorgAstroidManagerTC(unittest.TestCase): + + def test_borg(self): + """test that the AstroidManager is really a borg, i.e. that two different + instances has same cache""" + first_manager = AstroidManager() + built = first_manager.ast_from_module_name(BUILTINS) + + second_manager = AstroidManager() + second_built = second_manager.ast_from_module_name(BUILTINS) + self.assertIs(built, second_built) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_modutils.py astroid-1.3.8/astroid/tests/unittest_modutils.py --- astroid-1.0.1/astroid/tests/unittest_modutils.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_modutils.py 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,262 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 2.1 of the License, or (at your option) any +# later version. +# +# astroid is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +""" +unit tests for module modutils (module manipulation utilities) +""" +import os +import sys +import unittest + +from logilab.common import configuration +from astroid import modutils +from astroid.tests import resources + + +class ModuleFileTest(unittest.TestCase): + package = "mypypa" + + def tearDown(self): + for k in list(sys.path_importer_cache.keys()): + if 'MyPyPa' in k: + del sys.path_importer_cache[k] + + def test_find_zipped_module(self): + mtype, mfile = modutils._module_file( + [self.package], [resources.find('data/MyPyPa-0.1.0-py2.5.zip')]) + self.assertEqual(mtype, modutils.PY_ZIPMODULE) + self.assertEqual(mfile.split(os.sep)[-3:], ["data", "MyPyPa-0.1.0-py2.5.zip", self.package]) + + def test_find_egg_module(self): + mtype, mfile = modutils._module_file( + [self.package], [resources.find('data/MyPyPa-0.1.0-py2.5.egg')]) + self.assertEqual(mtype, modutils.PY_ZIPMODULE) + self.assertEqual(mfile.split(os.sep)[-3:], ["data", "MyPyPa-0.1.0-py2.5.egg", self.package]) + + +class LoadModuleFromNameTest(unittest.TestCase): + """ load a python module from it's name """ + + def test_knownValues_load_module_from_name_1(self): + self.assertEqual(modutils.load_module_from_name('sys'), sys) + + def test_knownValues_load_module_from_name_2(self): + self.assertEqual(modutils.load_module_from_name('os.path'), os.path) + + def test_raise_load_module_from_name_1(self): + self.assertRaises(ImportError, + modutils.load_module_from_name, 'os.path', use_sys=0) + + +class GetModulePartTest(unittest.TestCase): + """given a dotted name return the module part of the name""" + + def test_knownValues_get_module_part_1(self): + self.assertEqual(modutils.get_module_part('astroid.modutils'), + 'astroid.modutils') + + def test_knownValues_get_module_part_2(self): + self.assertEqual(modutils.get_module_part('astroid.modutils.get_module_part'), + 'astroid.modutils') + + def test_knownValues_get_module_part_3(self): + """relative import from given file""" + self.assertEqual(modutils.get_module_part('node_classes.AssName', + modutils.__file__), 'node_classes') + + def test_knownValues_get_compiled_module_part(self): + self.assertEqual(modutils.get_module_part('math.log10'), 'math') + self.assertEqual(modutils.get_module_part('math.log10', __file__), 'math') + + def test_knownValues_get_builtin_module_part(self): + self.assertEqual(modutils.get_module_part('sys.path'), 'sys') + self.assertEqual(modutils.get_module_part('sys.path', '__file__'), 'sys') + + def test_get_module_part_exception(self): + self.assertRaises(ImportError, modutils.get_module_part, 'unknown.module', + modutils.__file__) + + +class ModPathFromFileTest(unittest.TestCase): + """ given an absolute file path return the python module's path as a list """ + + def test_knownValues_modpath_from_file_1(self): + self.assertEqual(modutils.modpath_from_file(configuration.__file__), + ['logilab', 'common', 'configuration']) + + def test_knownValues_modpath_from_file_2(self): + self.assertEqual(modutils.modpath_from_file('unittest_modutils.py', + {os.getcwd(): 'arbitrary.pkg'}), + ['arbitrary', 'pkg', 'unittest_modutils']) + + def test_raise_modpath_from_file_Exception(self): + self.assertRaises(Exception, modutils.modpath_from_file, '/turlututu') + + +class LoadModuleFromPathTest(resources.SysPathSetup, unittest.TestCase): + + def test_do_not_load_twice(self): + modutils.load_module_from_modpath(['data', 'lmfp', 'foo']) + modutils.load_module_from_modpath(['data', 'lmfp']) + self.assertEqual(len(sys.just_once), 1) + del sys.just_once + + +class FileFromModPathTest(resources.SysPathSetup, unittest.TestCase): + """given a mod path (i.e. splited module / package name), return the + corresponding file, giving priority to source file over precompiled file + if it exists""" + + def test_site_packages(self): + self.assertEqual(os.path.realpath(modutils.file_from_modpath(['astroid', 'modutils'])), + os.path.realpath(modutils.__file__.replace('.pyc', '.py'))) + + def test_std_lib(self): + from os import path + self.assertEqual(os.path.realpath(modutils.file_from_modpath(['os', 'path']).replace('.pyc', '.py')), + os.path.realpath(path.__file__.replace('.pyc', '.py'))) + + def test_xmlplus(self): + try: + # don't fail if pyxml isn't installed + from xml.dom import ext + except ImportError: + pass + else: + self.assertEqual(os.path.realpath(modutils.file_from_modpath(['xml', 'dom', 'ext']).replace('.pyc', '.py')), + os.path.realpath(ext.__file__.replace('.pyc', '.py'))) + + def test_builtin(self): + self.assertEqual(modutils.file_from_modpath(['sys']), + None) + + + def test_unexisting(self): + self.assertRaises(ImportError, modutils.file_from_modpath, ['turlututu']) + + def test_unicode_in_package_init(self): + # file_from_modpath should not crash when reading an __init__ + # file with unicode characters. + modutils.file_from_modpath(["data", "unicode_package", "core"]) + + +class GetSourceFileTest(unittest.TestCase): + + def test(self): + self.assertEqual(modutils.get_source_file(os.path.__file__), + os.path.normpath(os.path.__file__.replace('.pyc', '.py'))) + + def test_raise(self): + self.assertRaises(modutils.NoSourceFile, modutils.get_source_file, 'whatever') + + +class StandardLibModuleTest(resources.SysPathSetup, unittest.TestCase): + """ + return true if the module may be considered as a module from the standard + library + """ + + def test_builtins(self): + if sys.version_info < (3, 0): + self.assertEqual(modutils.is_standard_module('__builtin__'), True) + self.assertEqual(modutils.is_standard_module('builtins'), False) + else: + self.assertEqual(modutils.is_standard_module('__builtin__'), False) + self.assertEqual(modutils.is_standard_module('builtins'), True) + + def test_builtin(self): + self.assertEqual(modutils.is_standard_module('sys'), True) + + def test_nonstandard(self): + self.assertEqual(modutils.is_standard_module('logilab'), False) + + def test_unknown(self): + self.assertEqual(modutils.is_standard_module('unknown'), False) + + def test_builtin(self): + self.assertEqual(modutils.is_standard_module('marshal'), True) + + def test_4(self): + self.assertEqual(modutils.is_standard_module('hashlib'), True) + self.assertEqual(modutils.is_standard_module('pickle'), True) + self.assertEqual(modutils.is_standard_module('email'), True) + self.assertEqual(modutils.is_standard_module('io'), sys.version_info >= (2, 6)) + self.assertEqual(modutils.is_standard_module('StringIO'), sys.version_info < (3, 0)) + self.assertEqual(modutils.is_standard_module('unicodedata'), True) + + def test_custom_path(self): + datadir = resources.find('') + if datadir.startswith(modutils.EXT_LIB_DIR): + self.skipTest('known breakage of is_standard_module on installed package') + self.assertEqual(modutils.is_standard_module('data.module', (datadir,)), True) + self.assertEqual(modutils.is_standard_module('data.module', (os.path.abspath(datadir),)), True) + + def test_failing_edge_cases(self): + from logilab import common + # using a subpackage/submodule path as std_path argument + self.assertEqual(modutils.is_standard_module('logilab.common', common.__path__), False) + # using a module + object name as modname argument + self.assertEqual(modutils.is_standard_module('sys.path'), True) + # this is because only the first package/module is considered + self.assertEqual(modutils.is_standard_module('sys.whatever'), True) + self.assertEqual(modutils.is_standard_module('logilab.whatever', common.__path__), False) + + +class IsRelativeTest(unittest.TestCase): + + + def test_knownValues_is_relative_1(self): + import email + self.assertEqual(modutils.is_relative('utils', email.__path__[0]), + True) + + def test_knownValues_is_relative_2(self): + from logilab.common import tree + self.assertEqual(modutils.is_relative('modutils', tree.__file__), + True) + + def test_knownValues_is_relative_3(self): + import astroid + self.assertEqual(modutils.is_relative('astroid', astroid.__path__[0]), + False) + + +class GetModuleFilesTest(unittest.TestCase): + + def test_get_module_files_1(self): + """given a directory return a list of all available python module's files, even + in subdirectories + """ + package = resources.find('data/find_test') + modules = set(modutils.get_module_files(package, [])) + self.assertEqual( + modules, + {os.path.join(package, x) for x in ['__init__.py', 'module.py', 'module2.py', 'noendingnewline.py', 'nonregr.py']}) + + def test_load_module_set_attribute(self): + import logilab.common.fileutils + import logilab + del logilab.common.fileutils + del sys.modules['logilab.common.fileutils'] + m = modutils.load_module_from_modpath(['logilab', 'common', 'fileutils']) + self.assertTrue(hasattr(logilab, 'common')) + self.assertTrue(hasattr(logilab.common, 'fileutils')) + self.assertTrue(m is logilab.common.fileutils) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_nodes.py astroid-1.3.8/astroid/tests/unittest_nodes.py --- astroid-1.0.1/astroid/tests/unittest_nodes.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_nodes.py 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,459 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""tests for specific behaviour of astroid nodes +""" +import os +import sys +import unittest +import textwrap + +from astroid.node_classes import unpack_infer +from astroid.bases import BUILTINS, InferenceContext +from astroid.exceptions import NotFoundError +from astroid import bases +from astroid import builder +from astroid import nodes +from astroid import test_utils +from astroid.tests import resources + +abuilder = builder.AstroidBuilder() + + +class AsStringTest(resources.SysPathSetup, unittest.TestCase): + + def test_tuple_as_string(self): + def build(string): + return abuilder.string_build(string).body[0].value + + self.assertEqual(build('1,').as_string(), '(1, )') + self.assertEqual(build('1, 2, 3').as_string(), '(1, 2, 3)') + self.assertEqual(build('(1, )').as_string(), '(1, )') + self.assertEqual(build('1, 2, 3').as_string(), '(1, 2, 3)') + + def test_varargs_kwargs_as_string(self): + ast = abuilder.string_build('raise_string(*args, **kwargs)').body[0] + self.assertEqual(ast.as_string(), 'raise_string(*args, **kwargs)') + + def test_module_as_string(self): + """check as_string on a whole module prepared to be returned identically + """ + module = resources.build_file('data/module.py', 'data.module') + with open(resources.find('data/module.py'), 'r') as fobj: + self.assertMultiLineEqual(module.as_string(), fobj.read()) + + def test_module2_as_string(self): + """check as_string on a whole module prepared to be returned identically + """ + module2 = resources.build_file('data/module2.py', 'data.module2') + with open(resources.find('data/module2.py'), 'r') as fobj: + self.assertMultiLineEqual(module2.as_string(), fobj.read()) + + def test_as_string(self): + """check as_string for python syntax >= 2.7""" + code = '''one_two = {1, 2} +b = {v: k for (k, v) in enumerate('string')} +cdd = {k for k in b}\n\n''' + ast = abuilder.string_build(code) + self.assertMultiLineEqual(ast.as_string(), code) + + @test_utils.require_version('3.0') + def test_3k_as_string(self): + """check as_string for python 3k syntax""" + code = '''print() + +def function(var): + nonlocal counter + try: + hello + except NameError as nexc: + (*hell, o) = b'hello' + raise AttributeError from nexc +\n''' + ast = abuilder.string_build(code) + self.assertEqual(ast.as_string(), code) + + @test_utils.require_version('3.0') + @unittest.expectedFailure + def test_3k_annotations_and_metaclass(self): + code_annotations = textwrap.dedent(''' + def function(var:int): + nonlocal counter + + class Language(metaclass=Natural): + """natural language""" + ''') + + ast = abuilder.string_build(code_annotations) + self.assertEqual(ast.as_string(), code_annotations) + + def test_ellipsis(self): + ast = abuilder.string_build('a[...]').body[0] + self.assertEqual(ast.as_string(), 'a[...]') + + def test_slices(self): + for code in ('a[0]', 'a[1:3]', 'a[:-1:step]', 'a[:,newaxis]', + 'a[newaxis,:]', 'del L[::2]', 'del A[1]', 'del Br[:]'): + ast = abuilder.string_build(code).body[0] + self.assertEqual(ast.as_string(), code) + + def test_slice_and_subscripts(self): + code = """a[:1] = bord[2:] +a[:1] = bord[2:] +del bree[3:d] +bord[2:] +del av[d::f], a[df:] +a[:1] = bord[2:] +del SRC[::1,newaxis,1:] +tous[vals] = 1010 +del thousand[key] +del a[::2], a[:-1:step] +del Fee.form[left:] +aout.vals = miles.of_stuff +del (ccok, (name.thing, foo.attrib.value)), Fee.form[left:] +if all[1] == bord[0:]: + pass\n\n""" + ast = abuilder.string_build(code) + self.assertEqual(ast.as_string(), code) + + +class _NodeTest(unittest.TestCase): + """test transformation of If Node""" + CODE = None + + @property + def astroid(self): + try: + return self.__class__.__dict__['CODE_Astroid'] + except KeyError: + astroid = test_utils.build_module(self.CODE) + self.__class__.CODE_Astroid = astroid + return astroid + + +class IfNodeTest(_NodeTest): + """test transformation of If Node""" + CODE = """ + if 0: + print() + + if True: + print() + else: + pass + + if "": + print() + elif []: + raise + + if 1: + print() + elif True: + print() + elif func(): + pass + else: + raise + """ + + def test_if_elif_else_node(self): + """test transformation for If node""" + self.assertEqual(len(self.astroid.body), 4) + for stmt in self.astroid.body: + self.assertIsInstance(stmt, nodes.If) + self.assertFalse(self.astroid.body[0].orelse) # simple If + self.assertIsInstance(self.astroid.body[1].orelse[0], nodes.Pass) # If / else + self.assertIsInstance(self.astroid.body[2].orelse[0], nodes.If) # If / elif + self.assertIsInstance(self.astroid.body[3].orelse[0].orelse[0], nodes.If) + + def test_block_range(self): + # XXX ensure expected values + self.assertEqual(self.astroid.block_range(1), (0, 22)) + self.assertEqual(self.astroid.block_range(10), (0, 22)) # XXX (10, 22) ? + self.assertEqual(self.astroid.body[1].block_range(5), (5, 6)) + self.assertEqual(self.astroid.body[1].block_range(6), (6, 6)) + self.assertEqual(self.astroid.body[1].orelse[0].block_range(7), (7, 8)) + self.assertEqual(self.astroid.body[1].orelse[0].block_range(8), (8, 8)) + + +class TryExceptNodeTest(_NodeTest): + CODE = """ + try: + print ('pouet') + except IOError: + pass + except UnicodeError: + print() + else: + print() + """ + + def test_block_range(self): + # XXX ensure expected values + self.assertEqual(self.astroid.body[0].block_range(1), (1, 8)) + self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) + self.assertEqual(self.astroid.body[0].block_range(3), (3, 8)) + self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) + self.assertEqual(self.astroid.body[0].block_range(5), (5, 5)) + self.assertEqual(self.astroid.body[0].block_range(6), (6, 6)) + self.assertEqual(self.astroid.body[0].block_range(7), (7, 7)) + self.assertEqual(self.astroid.body[0].block_range(8), (8, 8)) + + +class TryFinallyNodeTest(_NodeTest): + CODE = """ + try: + print ('pouet') + finally: + print ('pouet') + """ + + def test_block_range(self): + # XXX ensure expected values + self.assertEqual(self.astroid.body[0].block_range(1), (1, 4)) + self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) + self.assertEqual(self.astroid.body[0].block_range(3), (3, 4)) + self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) + + +class TryExceptFinallyNodeTest(_NodeTest): + CODE = """ + try: + print('pouet') + except Exception: + print ('oops') + finally: + print ('pouet') + """ + + def test_block_range(self): + # XXX ensure expected values + self.assertEqual(self.astroid.body[0].block_range(1), (1, 6)) + self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) + self.assertEqual(self.astroid.body[0].block_range(3), (3, 4)) + self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) + self.assertEqual(self.astroid.body[0].block_range(5), (5, 5)) + self.assertEqual(self.astroid.body[0].block_range(6), (6, 6)) + + +class TryExcept2xNodeTest(_NodeTest): + CODE = """ + try: + hello + except AttributeError, (retval, desc): + pass + """ + def test_tuple_attribute(self): + if sys.version_info >= (3, 0): + self.skipTest('syntax removed from py3.x') + handler = self.astroid.body[0].handlers[0] + self.assertIsInstance(handler.name, nodes.Tuple) + + +class ImportNodeTest(resources.SysPathSetup, unittest.TestCase): + def setUp(self): + super(ImportNodeTest, self).setUp() + self.module = resources.build_file('data/module.py', 'data.module') + self.module2 = resources.build_file('data/module2.py', 'data.module2') + + def test_import_self_resolve(self): + myos = next(self.module2.igetattr('myos')) + self.assertTrue(isinstance(myos, nodes.Module), myos) + self.assertEqual(myos.name, 'os') + self.assertEqual(myos.qname(), 'os') + self.assertEqual(myos.pytype(), '%s.module' % BUILTINS) + + def test_from_self_resolve(self): + pb = next(self.module.igetattr('pb')) + self.assertTrue(isinstance(pb, nodes.Class), pb) + self.assertEqual(pb.root().name, 'logilab.common.shellutils') + self.assertEqual(pb.qname(), 'logilab.common.shellutils.ProgressBar') + if pb.newstyle: + self.assertEqual(pb.pytype(), '%s.type' % BUILTINS) + else: + self.assertEqual(pb.pytype(), '%s.classobj' % BUILTINS) + abspath = next(self.module2.igetattr('abspath')) + self.assertTrue(isinstance(abspath, nodes.Function), abspath) + self.assertEqual(abspath.root().name, 'os.path') + self.assertEqual(abspath.qname(), 'os.path.abspath') + self.assertEqual(abspath.pytype(), '%s.function' % BUILTINS) + + def test_real_name(self): + from_ = self.module['pb'] + self.assertEqual(from_.real_name('pb'), 'ProgressBar') + imp_ = self.module['os'] + self.assertEqual(imp_.real_name('os'), 'os') + self.assertRaises(NotFoundError, imp_.real_name, 'os.path') + imp_ = self.module['pb'] + self.assertEqual(imp_.real_name('pb'), 'ProgressBar') + self.assertRaises(NotFoundError, imp_.real_name, 'ProgressBar') + imp_ = self.module2['YO'] + self.assertEqual(imp_.real_name('YO'), 'YO') + self.assertRaises(NotFoundError, imp_.real_name, 'data') + + def test_as_string(self): + ast = self.module['modutils'] + self.assertEqual(ast.as_string(), "from astroid import modutils") + ast = self.module['pb'] + self.assertEqual(ast.as_string(), "from logilab.common.shellutils import ProgressBar as pb") + ast = self.module['os'] + self.assertEqual(ast.as_string(), "import os.path") + code = """from . import here +from .. import door +from .store import bread +from ..cave import wine\n\n""" + ast = abuilder.string_build(code) + self.assertMultiLineEqual(ast.as_string(), code) + + def test_bad_import_inference(self): + # Explication of bug + '''When we import PickleError from nonexistent, a call to the infer + method of this From node will be made by unpack_infer. + inference.infer_from will try to import this module, which will fail and + raise a InferenceException (by mixins.do_import_module). The infer_name + will catch this exception and yield and YES instead. + ''' + + code = ''' + try: + from pickle import PickleError + except ImportError: + from nonexistent import PickleError + + try: + pass + except PickleError: + pass + ''' + astroid = test_utils.build_module(code) + handler_type = astroid.body[1].handlers[0].type + + excs = list(unpack_infer(handler_type)) + # The number of returned object can differ on Python 2 + # and Python 3. In one version, an additional item will + # be returned, from the _pickle module, which is not + # present in the other version. + self.assertIsInstance(excs[0], nodes.Class) + self.assertEqual(excs[0].name, 'PickleError') + self.assertIs(excs[-1], bases.YES) + + def test_absolute_import(self): + astroid = resources.build_file('data/absimport.py') + ctx = InferenceContext() + # will fail if absolute import failed + ctx.lookupname = 'message' + next(astroid['message'].infer(ctx)) + ctx.lookupname = 'email' + m = next(astroid['email'].infer(ctx)) + self.assertFalse(m.file.startswith(os.path.join('data', 'email.py'))) + + def test_more_absolute_import(self): + astroid = resources.build_file('data/module1abs/__init__.py', 'data.module1abs') + self.assertIn('sys', astroid.locals) + + +class CmpNodeTest(unittest.TestCase): + def test_as_string(self): + ast = abuilder.string_build("a == 2").body[0] + self.assertEqual(ast.as_string(), "a == 2") + + +class ConstNodeTest(unittest.TestCase): + + def _test(self, value): + node = nodes.const_factory(value) + self.assertIsInstance(node._proxied, nodes.Class) + self.assertEqual(node._proxied.name, value.__class__.__name__) + self.assertIs(node.value, value) + self.assertTrue(node._proxied.parent) + self.assertEqual(node._proxied.root().name, value.__class__.__module__) + + def test_none(self): + self._test(None) + + def test_bool(self): + self._test(True) + + def test_int(self): + self._test(1) + + def test_float(self): + self._test(1.0) + + def test_complex(self): + self._test(1.0j) + + def test_str(self): + self._test('a') + + def test_unicode(self): + self._test(u'a') + + +class NameNodeTest(unittest.TestCase): + def test_assign_to_True(self): + """test that True and False assignements don't crash""" + code = """ + True = False + def hello(False): + pass + del True + """ + if sys.version_info >= (3, 0): + with self.assertRaises(SyntaxError): + test_utils.build_module(code) + else: + ast = test_utils.build_module(code) + ass_true = ast['True'] + self.assertIsInstance(ass_true, nodes.AssName) + self.assertEqual(ass_true.name, "True") + del_true = ast.body[2].targets[0] + self.assertIsInstance(del_true, nodes.DelName) + self.assertEqual(del_true.name, "True") + + +class ArgumentsNodeTC(unittest.TestCase): + def test_linenumbering(self): + ast = test_utils.build_module(''' + def func(a, + b): pass + x = lambda x: None + ''') + self.assertEqual(ast['func'].args.fromlineno, 2) + self.assertFalse(ast['func'].args.is_statement) + xlambda = next(ast['x'].infer()) + self.assertEqual(xlambda.args.fromlineno, 4) + self.assertEqual(xlambda.args.tolineno, 4) + self.assertFalse(xlambda.args.is_statement) + if sys.version_info < (3, 0): + self.assertEqual(ast['func'].args.tolineno, 3) + else: + 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) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_peephole.py astroid-1.3.8/astroid/tests/unittest_peephole.py --- astroid-1.0.1/astroid/tests/unittest_peephole.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_peephole.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,120 @@ +# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . + +"""Tests for the astroid AST peephole optimizer.""" + +import ast +import textwrap +import unittest + +import astroid +from astroid import astpeephole +from astroid import manager +from astroid import test_utils +from astroid.tests import resources + + +MANAGER = manager.AstroidManager() + + +class PeepholeOptimizer(unittest.TestCase): + @classmethod + def setUpClass(cls): + MANAGER.optimize_ast = True + + @classmethod + def tearDownClass(cls): + MANAGER.optimize_ast = False + + def setUp(self): + self._optimizer = astpeephole.ASTPeepholeOptimizer() + + @staticmethod + def _get_binops(code): + module = ast.parse(textwrap.dedent(code)) + return [node.value for node in module.body + if isinstance(node, ast.Expr)] + + @test_utils.require_version(maxver='3.0') + def test_optimize_binop_unicode(self): + nodes = self._get_binops(""" + u"a" + u"b" + u"c" + + u"a" + "c" + "b" + u"a" + b"c" + """) + + result = self._optimizer.optimize_binop(nodes[0]) + self.assertIsInstance(result, astroid.Const) + self.assertEqual(result.value, u"abc") + + self.assertIsNone(self._optimizer.optimize_binop(nodes[1])) + self.assertIsNone(self._optimizer.optimize_binop(nodes[2])) + + def test_optimize_binop(self): + nodes = self._get_binops(""" + "a" + "b" + "c" + "d" + b"a" + b"b" + b"c" + b"d" + "a" + "b" + + "a" + "b" + 1 + object + var = 4 + "a" + "b" + var + "c" + "a" + "b" + "c" - "4" + "a" + "b" + "c" + "d".format() + "a" - "b" + "a" + 1 + 4 + 5 + 6 + """) + + result = self._optimizer.optimize_binop(nodes[0]) + self.assertIsInstance(result, astroid.Const) + self.assertEqual(result.value, "abcd") + + result = self._optimizer.optimize_binop(nodes[1]) + self.assertIsInstance(result, astroid.Const) + self.assertEqual(result.value, b"abcd") + + for node in nodes[2:]: + self.assertIsNone(self._optimizer.optimize_binop(node)) + + def test_big_binop_crash(self): + # Test that we don't fail on a lot of joined strings + # through the addition operator. + module = resources.build_file('data/joined_strings.py') + element = next(module['x'].infer()) + self.assertIsInstance(element, astroid.Const) + self.assertEqual(len(element.value), 61660) + + def test_optimisation_disabled(self): + try: + MANAGER.optimize_ast = False + module = test_utils.build_module(""" + '1' + '2' + '3' + """) + self.assertIsInstance(module.body[0], astroid.Discard) + self.assertIsInstance(module.body[0].value, astroid.BinOp) + self.assertIsInstance(module.body[0].value.left, astroid.BinOp) + self.assertIsInstance(module.body[0].value.left.left, + astroid.Const) + finally: + MANAGER.optimize_ast = True + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_protocols.py astroid-1.3.8/astroid/tests/unittest_protocols.py --- astroid-1.0.1/astroid/tests/unittest_protocols.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_protocols.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,153 @@ +# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . + +import unittest + +from astroid import YES +from astroid.test_utils import extract_node, require_version +from astroid import InferenceError +from astroid.node_classes import AssName, Const, Name, Starred + + +class ProtocolTests(unittest.TestCase): + + def assertConstNodesEqual(self, nodes_list_expected, nodes_list_got): + self.assertEqual(len(nodes_list_expected), len(nodes_list_got)) + for node in nodes_list_got: + self.assertIsInstance(node, Const) + for node, expected_value in zip(nodes_list_got, nodes_list_expected): + self.assertEqual(expected_value, node.value) + + def assertNameNodesEqual(self, nodes_list_expected, nodes_list_got): + self.assertEqual(len(nodes_list_expected), len(nodes_list_got)) + for node in nodes_list_got: + self.assertIsInstance(node, Name) + for node, expected_name in zip(nodes_list_got, nodes_list_expected): + self.assertEqual(expected_name, node.name) + + def test_assigned_stmts_simple_for(self): + assign_stmts = extract_node(""" + for a in (1, 2, 3): #@ + pass + + for b in range(3): #@ + pass + """) + + for1_assnode = next(assign_stmts[0].nodes_of_class(AssName)) + assigned = list(for1_assnode.assigned_stmts()) + self.assertConstNodesEqual([1, 2, 3], assigned) + + for2_assnode = next(assign_stmts[1].nodes_of_class(AssName)) + self.assertRaises(InferenceError, + list, for2_assnode.assigned_stmts()) + + @require_version(minver='3.0') + def test_assigned_stmts_starred_for(self): + assign_stmts = extract_node(""" + for *a, b in ((1, 2, 3), (4, 5, 6, 7)): #@ + pass + """) + + for1_starred = next(assign_stmts.nodes_of_class(Starred)) + assigned = list(for1_starred.assigned_stmts()) + self.assertEqual(assigned, []) + + def _get_starred_stmts(self, code, expected): + assign_stmt = extract_node("{} #@".format(code)) + starred = next(assign_stmt.nodes_of_class(Starred)) + return list(starred.assigned_stmts()) + + def _helper_starred_expected_const(self, code, expected): + stmts = self._get_starred_stmts(code, expected) + self.assertConstNodesEqual(expected, stmts) + + def _helper_starred_expected(self, code, expected): + stmts = self._get_starred_stmts(code, expected) + self.assertEqual(expected, stmts) + + def _helper_starred_inference_error(self, code): + assign_stmt = extract_node("{} #@".format(code)) + starred = next(assign_stmt.nodes_of_class(Starred)) + self.assertRaises(InferenceError, list, starred.assigned_stmts()) + + @require_version(minver='3.0') + def test_assigned_stmts_starred_assnames(self): + self._helper_starred_expected_const( + "a, *b = (1, 2, 3, 4) #@", [2, 3, 4]) + self._helper_starred_expected_const( + "*a, b = (1, 2, 3) #@", [1, 2]) + self._helper_starred_expected_const( + "a, *b, c = (1, 2, 3, 4, 5) #@", + [2, 3, 4]) + self._helper_starred_expected_const( + "a, *b = (1, 2) #@", [2]) + self._helper_starred_expected_const( + "*b, a = (1, 2) #@", [1]) + self._helper_starred_expected_const( + "[*b] = (1, 2) #@", [1, 2]) + + @require_version(minver='3.0') + def test_assigned_stmts_starred_yes(self): + # Not something iterable and known + self._helper_starred_expected("a, *b = range(3) #@", [YES]) + # Not something inferrable + self._helper_starred_expected("a, *b = balou() #@", [YES]) + # In function, unknown. + self._helper_starred_expected(""" + def test(arg): + head, *tail = arg #@""", [YES]) + # These cases aren't worth supporting. + self._helper_starred_expected( + "a, (*b, c), d = (1, (2, 3, 4), 5) #@", []) + + @require_version(minver='3.0') + def test_assign_stmts_starred_fails(self): + # Too many starred + self._helper_starred_inference_error("a, *b, *c = (1, 2, 3) #@") + # Too many lhs values + self._helper_starred_inference_error("a, *b, c = (1, 2) #@") + # Not in Assign or For + self._helper_starred_inference_error("[*b for b in (1, 2, 3)] #@") + # This could be solved properly, but it complicates needlessly the + # code for assigned_stmts, without oferring real benefit. + self._helper_starred_inference_error( + "(*a, b), (c, *d) = (1, 2, 3), (4, 5, 6) #@") + + def test_assigned_stmts_assignments(self): + assign_stmts = extract_node(""" + c = a #@ + + d, e = b, c #@ + """) + + simple_assnode = next(assign_stmts[0].nodes_of_class(AssName)) + assigned = list(simple_assnode.assigned_stmts()) + self.assertNameNodesEqual(['a'], assigned) + + assnames = assign_stmts[1].nodes_of_class(AssName) + simple_mul_assnode_1 = next(assnames) + assigned = list(simple_mul_assnode_1.assigned_stmts()) + self.assertNameNodesEqual(['b'], assigned) + simple_mul_assnode_2 = next(assnames) + assigned = list(simple_mul_assnode_2.assigned_stmts()) + self.assertNameNodesEqual(['c'], assigned) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_python3.py astroid-1.3.8/astroid/tests/unittest_python3.py --- astroid-1.0.1/astroid/tests/unittest_python3.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_python3.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,218 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +from textwrap import dedent +import unittest + +from astroid.node_classes import Assign, Discard, YieldFrom, Name, Const +from astroid.builder import AstroidBuilder +from astroid.scoped_nodes import Class, Function +from astroid.test_utils import require_version + + +class Python3TC(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.builder = AstroidBuilder() + + @require_version('3.0') + def test_starred_notation(self): + astroid = self.builder.string_build("*a, b = [1, 2, 3]", 'test', 'test') + + # Get the star node + node = next(next(next(astroid.get_children()).get_children()).get_children()) + + self.assertTrue(isinstance(node.ass_type(), Assign)) + + @require_version('3.3') + def test_yield_from(self): + body = dedent(""" + def func(): + yield from iter([1, 2]) + """) + astroid = self.builder.string_build(body) + func = astroid.body[0] + self.assertIsInstance(func, Function) + yieldfrom_stmt = func.body[0] + + self.assertIsInstance(yieldfrom_stmt, Discard) + self.assertIsInstance(yieldfrom_stmt.value, YieldFrom) + self.assertEqual(yieldfrom_stmt.as_string(), + 'yield from iter([1, 2])') + + @require_version('3.3') + def test_yield_from_is_generator(self): + body = dedent(""" + def func(): + yield from iter([1, 2]) + """) + astroid = self.builder.string_build(body) + func = astroid.body[0] + self.assertIsInstance(func, Function) + self.assertTrue(func.is_generator()) + + @require_version('3.3') + def test_yield_from_as_string(self): + body = dedent(""" + def func(): + yield from iter([1, 2]) + value = yield from other() + """) + astroid = self.builder.string_build(body) + func = astroid.body[0] + self.assertEqual(func.as_string().strip(), body.strip()) + + # metaclass tests + + @require_version('3.0') + def test_simple_metaclass(self): + astroid = self.builder.string_build("class Test(metaclass=type): pass") + klass = astroid.body[0] + + metaclass = klass.metaclass() + self.assertIsInstance(metaclass, Class) + self.assertEqual(metaclass.name, 'type') + + @require_version('3.0') + def test_metaclass_error(self): + astroid = self.builder.string_build("class Test(metaclass=typ): pass") + klass = astroid.body[0] + self.assertFalse(klass.metaclass()) + + @require_version('3.0') + def test_metaclass_imported(self): + astroid = self.builder.string_build(dedent(""" + from abc import ABCMeta + class Test(metaclass=ABCMeta): pass""")) + klass = astroid.body[1] + + metaclass = klass.metaclass() + self.assertIsInstance(metaclass, Class) + self.assertEqual(metaclass.name, 'ABCMeta') + + @require_version('3.0') + def test_as_string(self): + body = dedent(""" + from abc import ABCMeta + class Test(metaclass=ABCMeta): pass""") + astroid = self.builder.string_build(body) + klass = astroid.body[1] + + self.assertEqual(klass.as_string(), + '\n\nclass Test(metaclass=ABCMeta):\n pass\n') + + @require_version('3.0') + def test_old_syntax_works(self): + astroid = self.builder.string_build(dedent(""" + class Test: + __metaclass__ = type + class SubTest(Test): pass + """)) + klass = astroid['SubTest'] + metaclass = klass.metaclass() + self.assertIsNone(metaclass) + + @require_version('3.0') + def test_metaclass_yes_leak(self): + astroid = self.builder.string_build(dedent(""" + # notice `ab` instead of `abc` + from ab import ABCMeta + + class Meta(metaclass=ABCMeta): pass + """)) + klass = astroid['Meta'] + self.assertIsNone(klass.metaclass()) + + @require_version('3.0') + def test_parent_metaclass(self): + astroid = self.builder.string_build(dedent(""" + from abc import ABCMeta + class Test(metaclass=ABCMeta): pass + class SubTest(Test): pass + """)) + klass = astroid['SubTest'] + self.assertTrue(klass.newstyle) + metaclass = klass.metaclass() + self.assertIsInstance(metaclass, Class) + self.assertEqual(metaclass.name, 'ABCMeta') + + @require_version('3.0') + def test_metaclass_ancestors(self): + astroid = self.builder.string_build(dedent(""" + from abc import ABCMeta + + class FirstMeta(metaclass=ABCMeta): pass + class SecondMeta(metaclass=type): + pass + + class Simple: + pass + + class FirstImpl(FirstMeta): pass + class SecondImpl(FirstImpl): pass + class ThirdImpl(Simple, SecondMeta): + pass + """)) + classes = { + 'ABCMeta': ('FirstImpl', 'SecondImpl'), + 'type': ('ThirdImpl', ) + } + for metaclass, names in classes.items(): + for name in names: + impl = astroid[name] + meta = impl.metaclass() + self.assertIsInstance(meta, Class) + self.assertEqual(meta.name, metaclass) + + @require_version('3.0') + def test_annotation_support(self): + astroid = self.builder.string_build(dedent(""" + def test(a: int, b: str, c: None, d, e, + *args: float, **kwargs: int)->int: + 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.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]) + + 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.assertIsNone(func.returns) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_raw_building.py astroid-1.3.8/astroid/tests/unittest_raw_building.py --- astroid-1.0.1/astroid/tests/unittest_raw_building.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_raw_building.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,48 @@ +import unittest + +from astroid.raw_building import (attach_dummy_node, build_module, build_class, build_function, build_from_import) + +class RawBuildingTC(unittest.TestCase): + + def test_attach_dummy_node(self): + node = build_module('MyModule') + dummy = attach_dummy_node(node, 'DummyNode') + self.assertEqual(1, len(list(node.get_children()))) + + def test_build_module(self): + node = build_module('MyModule') + self.assertEqual(node.name, 'MyModule') + self.assertEqual(node.pure_python, False) + self.assertEqual(node.package, False) + self.assertEqual(node.parent, None) + + def test_build_class(self): + node = build_class('MyClass') + self.assertEqual(node.name, 'MyClass') + self.assertEqual(node.doc, None) + + def test_build_function(self): + node = build_function('MyFunction') + self.assertEqual(node.name, 'MyFunction') + self.assertEqual(node.doc, None) + + def test_build_function_args(self): + args = ['myArgs1', 'myArgs2'] + node = build_function('MyFunction', args) + self.assertEqual('myArgs1', node.args.args[0].name) + self.assertEqual('myArgs2', node.args.args[1].name) + self.assertEqual(2, len(node.args.args)) + + def test_build_function_defaults(self): + defaults = ['defaults1', 'defaults2'] + node = build_function('MyFunction', None, defaults) + self.assertEqual(2, len(node.args.defaults)) + + def test_build_from_import(self): + names = ['exceptions, inference, inspector'] + node = build_from_import('astroid', names) + self.assertEqual(len(names), len(node.names)) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_regrtest.py astroid-1.3.8/astroid/tests/unittest_regrtest.py --- astroid-1.0.1/astroid/tests/unittest_regrtest.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_regrtest.py 2015-08-02 20:37:37.000000000 +0000 @@ -0,0 +1,276 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +import sys +import unittest +import textwrap + +import six + +from astroid import MANAGER, Instance, nodes +from astroid.bases import BUILTINS +from astroid.builder import AstroidBuilder +from astroid.raw_building import build_module +from astroid.manager import AstroidManager +from astroid.test_utils import require_version, extract_node +from astroid.tests import resources + +class NonRegressionTests(resources.AstroidCacheSetupMixin, + unittest.TestCase): + + def setUp(self): + sys.path.insert(0, resources.find('data')) + MANAGER.always_load_extensions = True + + def tearDown(self): + # Since we may have created a brainless manager, leading + # to a new cache builtin module and proxy classes in the constants, + # clear out the global manager cache. + MANAGER.clear_cache(self._builtins) + MANAGER.always_load_extensions = False + sys.path.pop(0) + sys.path_importer_cache.pop(resources.find('data'), None) + + def brainless_manager(self): + manager = AstroidManager() + # avoid caching into the AstroidManager borg since we get problems + # with other tests : + manager.__dict__ = {} + manager.astroid_cache = {} + manager._mod_file_cache = {} + manager.transforms = {} + manager.clear_cache() # trigger proper bootstraping + return manager + + def test_module_path(self): + man = self.brainless_manager() + mod = man.ast_from_module_name('package.import_package_subpackage_module') + package = next(mod.igetattr('package')) + self.assertEqual(package.name, 'package') + subpackage = next(package.igetattr('subpackage')) + self.assertIsInstance(subpackage, nodes.Module) + self.assertTrue(subpackage.package) + self.assertEqual(subpackage.name, 'package.subpackage') + module = next(subpackage.igetattr('module')) + self.assertEqual(module.name, 'package.subpackage.module') + + + def test_package_sidepackage(self): + manager = self.brainless_manager() + assert 'package.sidepackage' not in MANAGER.astroid_cache + package = manager.ast_from_module_name('absimp') + self.assertIsInstance(package, nodes.Module) + self.assertTrue(package.package) + subpackage = next(package.getattr('sidepackage')[0].infer()) + self.assertIsInstance(subpackage, nodes.Module) + self.assertTrue(subpackage.package) + self.assertEqual(subpackage.name, 'absimp.sidepackage') + + + def test_living_property(self): + builder = AstroidBuilder() + builder._done = {} + builder._module = sys.modules[__name__] + builder.object_build(build_module('module_name', ''), Whatever) + + + def test_new_style_class_detection(self): + try: + import pygtk # pylint: disable=unused-variable + except ImportError: + self.skipTest('test skipped: pygtk is not available') + # XXX may fail on some pygtk version, because objects in + # gobject._gobject have __module__ set to gobject :( + builder = AstroidBuilder() + data = """ +import pygtk +pygtk.require("2.6") +import gobject + +class A(gobject.GObject): + pass +""" + astroid = builder.string_build(data, __name__, __file__) + a = astroid['A'] + self.assertTrue(a.newstyle) + + + def test_pylint_config_attr(self): + try: + from pylint import lint # pylint: disable=unused-variable + except ImportError: + self.skipTest('pylint not available') + mod = MANAGER.ast_from_module_name('pylint.lint') + pylinter = mod['PyLinter'] + expect = ['OptionsManagerMixIn', 'object', 'MessagesHandlerMixIn', + 'ReportsHandlerMixIn', 'BaseTokenChecker', 'BaseChecker', + 'OptionsProviderMixIn'] + self.assertListEqual([c.name for c in pylinter.ancestors()], + expect) + self.assertTrue(list(Instance(pylinter).getattr('config'))) + infered = list(Instance(pylinter).igetattr('config')) + self.assertEqual(len(infered), 1) + self.assertEqual(infered[0].root().name, 'optparse') + self.assertEqual(infered[0].name, 'Values') + + def test_numpy_crash(self): + """test don't crash on numpy""" + #a crash occured somewhere in the past, and an + # InferenceError instead of a crash was better, but now we even infer! + try: + import numpy # pylint: disable=unused-variable + except ImportError: + self.skipTest('test skipped: numpy is not available') + builder = AstroidBuilder() + data = """ +from numpy import multiply + +multiply(1, 2, 3) +""" + astroid = builder.string_build(data, __name__, __file__) + callfunc = astroid.body[1].value.func + infered = callfunc.infered() + self.assertEqual(len(infered), 1) + + @require_version('3.0') + def test_nameconstant(self): + # used to fail for Python 3.4 + builder = AstroidBuilder() + astroid = builder.string_build("def test(x=True): pass") + default = astroid.body[0].args.args[0] + self.assertEqual(default.name, 'x') + self.assertEqual(next(default.infer()).value, True) + + @require_version('2.7') + def test_with_infer_assnames(self): + builder = AstroidBuilder() + data = """ +with open('a.txt') as stream, open('b.txt'): + stream.read() +""" + astroid = builder.string_build(data, __name__, __file__) + # Used to crash due to the fact that the second + # context manager didn't use an assignment name. + list(astroid.nodes_of_class(nodes.CallFunc))[-1].infered() + + def test_recursion_regression_issue25(self): + builder = AstroidBuilder() + data = """ +import recursion as base + +_real_Base = base.Base + +class Derived(_real_Base): + pass + +def run(): + base.Base = Derived +""" + astroid = builder.string_build(data, __name__, __file__) + # Used to crash in _is_metaclass, due to wrong + # ancestors chain + classes = astroid.nodes_of_class(nodes.Class) + for klass in classes: + # triggers the _is_metaclass call + klass.type + + def test_decorator_callchain_issue42(self): + builder = AstroidBuilder() + data = """ + +def test(): + def factory(func): + def newfunc(): + func() + return newfunc + return factory + +@test() +def crash(): + pass +""" + astroid = builder.string_build(data, __name__, __file__) + self.assertEqual(astroid['crash'].type, 'function') + + def test_filter_stmts_scoping(self): + builder = AstroidBuilder() + data = """ +def test(): + compiler = int() + class B(compiler.__class__): + pass + compiler = B() + return compiler +""" + astroid = builder.string_build(data, __name__, __file__) + test = astroid['test'] + result = next(test.infer_call_result(astroid)) + self.assertIsInstance(result, Instance) + base = next(result._proxied.bases[0].infer()) + self.assertEqual(base.name, 'int') + + def test_ancestors_patching_class_recursion(self): + node = AstroidBuilder().string_build(textwrap.dedent(""" + import string + Template = string.Template + + class A(Template): + pass + + class B(A): + pass + + def test(x=False): + if x: + string.Template = A + else: + string.Template = B + """)) + klass = node['A'] + ancestors = list(klass.ancestors()) + self.assertEqual(ancestors[0].qname(), 'string.Template') + + def test_ancestors_yes_in_bases(self): + # Test for issue https://bitbucket.org/logilab/astroid/issue/84 + # This used to crash astroid with a TypeError, because an YES + # node was present in the bases + node = extract_node(""" + def with_metaclass(meta, *bases): + class metaclass(meta): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) + + import lala + + class A(with_metaclass(object, lala.lala)): #@ + pass + """) + ancestors = list(node.ancestors()) + if six.PY3: + self.assertEqual(len(ancestors), 1) + self.assertEqual(ancestors[0].qname(), + "{}.object".format(BUILTINS)) + else: + self.assertEqual(len(ancestors), 0) + + +class Whatever(object): + a = property(lambda x: x, lambda x: x) + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_scoped_nodes.py astroid-1.3.8/astroid/tests/unittest_scoped_nodes.py --- astroid-1.0.1/astroid/tests/unittest_scoped_nodes.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_scoped_nodes.py 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,1197 @@ +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""tests for specific behaviour of astroid scoped nodes (i.e. module, class and +function) +""" +import os +import sys +from functools import partial +import unittest +import warnings + +from astroid import YES, builder, nodes, scoped_nodes, \ + InferenceError, NotFoundError, NoDefault, ResolveError +from astroid.bases import BUILTINS, Instance, BoundMethod, UnboundMethod +from astroid import __pkginfo__ +from astroid import test_utils +from astroid.tests import resources + + +def _test_dict_interface(self, node, test_attr): + self.assertIs(node[test_attr], node[test_attr]) + self.assertIn(test_attr, node) + node.keys() + node.values() + node.items() + iter(node) + + +class ModuleLoader(resources.SysPathSetup): + def setUp(self): + super(ModuleLoader, self).setUp() + self.module = resources.build_file('data/module.py', 'data.module') + self.module2 = resources.build_file('data/module2.py', 'data.module2') + self.nonregr = resources.build_file('data/nonregr.py', 'data.nonregr') + self.pack = resources.build_file('data/__init__.py', 'data') + + +class ModuleNodeTest(ModuleLoader, unittest.TestCase): + + def test_special_attributes(self): + self.assertEqual(len(self.module.getattr('__name__')), 1) + self.assertIsInstance(self.module.getattr('__name__')[0], nodes.Const) + self.assertEqual(self.module.getattr('__name__')[0].value, 'data.module') + self.assertEqual(len(self.module.getattr('__doc__')), 1) + self.assertIsInstance(self.module.getattr('__doc__')[0], nodes.Const) + self.assertEqual(self.module.getattr('__doc__')[0].value, 'test module for astroid\n') + self.assertEqual(len(self.module.getattr('__file__')), 1) + self.assertIsInstance(self.module.getattr('__file__')[0], nodes.Const) + self.assertEqual(self.module.getattr('__file__')[0].value, + os.path.abspath(resources.find('data/module.py'))) + self.assertEqual(len(self.module.getattr('__dict__')), 1) + self.assertIsInstance(self.module.getattr('__dict__')[0], nodes.Dict) + self.assertRaises(NotFoundError, self.module.getattr, '__path__') + self.assertEqual(len(self.pack.getattr('__path__')), 1) + self.assertIsInstance(self.pack.getattr('__path__')[0], nodes.List) + + def test_dict_interface(self): + _test_dict_interface(self, self.module, 'YO') + + def test_getattr(self): + yo = self.module.getattr('YO')[0] + self.assertIsInstance(yo, nodes.Class) + self.assertEqual(yo.name, 'YO') + red = next(self.module.igetattr('redirect')) + self.assertIsInstance(red, nodes.Function) + self.assertEqual(red.name, 'four_args') + pb = next(self.module.igetattr('pb')) + self.assertIsInstance(pb, nodes.Class) + self.assertEqual(pb.name, 'ProgressBar') + # resolve packageredirection + mod = resources.build_file('data/appl/myConnection.py', + 'data.appl.myConnection') + ssl = next(mod.igetattr('SSL1')) + cnx = next(ssl.igetattr('Connection')) + self.assertEqual(cnx.__class__, nodes.Class) + self.assertEqual(cnx.name, 'Connection') + self.assertEqual(cnx.root().name, 'data.SSL1.Connection1') + self.assertEqual(len(self.nonregr.getattr('enumerate')), 2) + # raise ResolveError + self.assertRaises(InferenceError, self.nonregr.igetattr, 'YOAA') + + def test_wildard_import_names(self): + m = resources.build_file('data/all.py', 'all') + self.assertEqual(m.wildcard_import_names(), ['Aaa', '_bla', 'name']) + m = resources.build_file('data/notall.py', 'notall') + res = sorted(m.wildcard_import_names()) + self.assertEqual(res, ['Aaa', 'func', 'name', 'other']) + + m = test_utils.build_module(''' + from missing import tzop + trop = "test" + __all__ = (trop, "test1", tzop, 42) + ''') + res = sorted(m.wildcard_import_names()) + self.assertEqual(res, ["test", "test1"]) + + m = test_utils.build_module(''' + test = tzop = 42 + __all__ = ('test', ) + ('tzop', ) + ''') + res = sorted(m.wildcard_import_names()) + self.assertEqual(res, ['test', 'tzop']) + + def test_module_getattr(self): + data = ''' + appli = application + appli += 2 + del appli + ''' + astroid = test_utils.build_module(data, __name__) + # test del statement not returned by getattr + self.assertEqual(len(astroid.getattr('appli')), 2, + astroid.getattr('appli')) + + def test_relative_to_absolute_name(self): + # package + mod = nodes.Module('very.multi.package', 'doc') + mod.package = True + modname = mod.relative_to_absolute_name('utils', 1) + self.assertEqual(modname, 'very.multi.package.utils') + modname = mod.relative_to_absolute_name('utils', 2) + self.assertEqual(modname, 'very.multi.utils') + modname = mod.relative_to_absolute_name('utils', 0) + self.assertEqual(modname, 'very.multi.package.utils') + modname = mod.relative_to_absolute_name('', 1) + self.assertEqual(modname, 'very.multi.package') + # non package + mod = nodes.Module('very.multi.module', 'doc') + mod.package = False + modname = mod.relative_to_absolute_name('utils', 0) + self.assertEqual(modname, 'very.multi.utils') + modname = mod.relative_to_absolute_name('utils', 1) + self.assertEqual(modname, 'very.multi.utils') + modname = mod.relative_to_absolute_name('utils', 2) + self.assertEqual(modname, 'very.utils') + modname = mod.relative_to_absolute_name('', 1) + self.assertEqual(modname, 'very.multi') + + def test_import_1(self): + data = '''from . import subpackage''' + sys.path.insert(0, resources.find('data')) + astroid = test_utils.build_module(data, 'package', 'data/package/__init__.py') + try: + m = astroid.import_module('', level=1) + self.assertEqual(m.name, 'package') + infered = list(astroid.igetattr('subpackage')) + self.assertEqual(len(infered), 1) + self.assertEqual(infered[0].name, 'package.subpackage') + finally: + del sys.path[0] + + + def test_import_2(self): + data = '''from . import subpackage as pouet''' + astroid = test_utils.build_module(data, 'package', 'data/package/__init__.py') + sys.path.insert(0, resources.find('data')) + try: + m = astroid.import_module('', level=1) + self.assertEqual(m.name, 'package') + infered = list(astroid.igetattr('pouet')) + self.assertEqual(len(infered), 1) + self.assertEqual(infered[0].name, 'package.subpackage') + finally: + del sys.path[0] + + + def test_file_stream_in_memory(self): + data = '''irrelevant_variable is irrelevant''' + astroid = test_utils.build_module(data, 'in_memory') + with warnings.catch_warnings(record=True): + self.assertEqual(astroid.file_stream.read().decode(), data) + + def test_file_stream_physical(self): + path = resources.find('data/all.py') + astroid = builder.AstroidBuilder().file_build(path, 'all') + with open(path, 'rb') as file_io: + with warnings.catch_warnings(record=True): + self.assertEqual(astroid.file_stream.read(), file_io.read()) + + def test_file_stream_api(self): + path = resources.find('data/all.py') + astroid = builder.AstroidBuilder().file_build(path, 'all') + if __pkginfo__.numversion >= (1, 6): + # file_stream is slated for removal in astroid 1.6. + with self.assertRaises(AttributeError): + astroid.file_stream + else: + # Until astroid 1.6, Module.file_stream will emit + # PendingDeprecationWarning in 1.4, DeprecationWarning + # in 1.5 and finally it will be removed in 1.6, leaving + # only Module.stream as the recommended way to retrieve + # its file stream. + with warnings.catch_warnings(record=True) as cm: + warnings.simplefilter("always") + self.assertIsNot(astroid.file_stream, astroid.file_stream) + self.assertGreater(len(cm), 1) + self.assertEqual(cm[0].category, PendingDeprecationWarning) + + def test_stream_api(self): + path = resources.find('data/all.py') + astroid = builder.AstroidBuilder().file_build(path, 'all') + stream = astroid.stream() + self.assertTrue(hasattr(stream, 'close')) + with stream: + with open(path, 'rb') as file_io: + self.assertEqual(stream.read(), file_io.read()) + + +class FunctionNodeTest(ModuleLoader, unittest.TestCase): + + def test_special_attributes(self): + func = self.module2['make_class'] + self.assertEqual(len(func.getattr('__name__')), 1) + self.assertIsInstance(func.getattr('__name__')[0], nodes.Const) + self.assertEqual(func.getattr('__name__')[0].value, 'make_class') + self.assertEqual(len(func.getattr('__doc__')), 1) + self.assertIsInstance(func.getattr('__doc__')[0], nodes.Const) + self.assertEqual(func.getattr('__doc__')[0].value, 'check base is correctly resolved to Concrete0') + self.assertEqual(len(self.module.getattr('__dict__')), 1) + self.assertIsInstance(self.module.getattr('__dict__')[0], nodes.Dict) + + def test_dict_interface(self): + _test_dict_interface(self, self.module['global_access'], 'local') + + def test_default_value(self): + func = self.module2['make_class'] + self.assertIsInstance(func.args.default_value('base'), nodes.Getattr) + self.assertRaises(NoDefault, func.args.default_value, 'args') + self.assertRaises(NoDefault, func.args.default_value, 'kwargs') + self.assertRaises(NoDefault, func.args.default_value, 'any') + #self.assertIsInstance(func.mularg_class('args'), nodes.Tuple) + #self.assertIsInstance(func.mularg_class('kwargs'), nodes.Dict) + #self.assertIsNone(func.mularg_class('base')) + + def test_navigation(self): + function = self.module['global_access'] + self.assertEqual(function.statement(), function) + l_sibling = function.previous_sibling() + # check taking parent if child is not a stmt + self.assertIsInstance(l_sibling, nodes.Assign) + child = function.args.args[0] + self.assertIs(l_sibling, child.previous_sibling()) + r_sibling = function.next_sibling() + self.assertIsInstance(r_sibling, nodes.Class) + self.assertEqual(r_sibling.name, 'YO') + self.assertIs(r_sibling, child.next_sibling()) + last = r_sibling.next_sibling().next_sibling().next_sibling() + self.assertIsInstance(last, nodes.Assign) + self.assertIsNone(last.next_sibling()) + first = l_sibling.previous_sibling().previous_sibling().previous_sibling().previous_sibling().previous_sibling() + self.assertIsNone(first.previous_sibling()) + + def test_nested_args(self): + if sys.version_info >= (3, 0): + self.skipTest("nested args has been removed in py3.x") + code = ''' + def nested_args(a, (b, c, d)): + "nested arguments test" + ''' + tree = test_utils.build_module(code) + func = tree['nested_args'] + self.assertEqual(sorted(func.locals), ['a', 'b', 'c', 'd']) + self.assertEqual(func.args.format_args(), 'a, (b, c, d)') + + def test_four_args(self): + func = self.module['four_args'] + #self.assertEqual(func.args.args, ['a', ('b', 'c', 'd')]) + local = sorted(func.keys()) + self.assertEqual(local, ['a', 'b', 'c', 'd']) + self.assertEqual(func.type, 'function') + + def test_format_args(self): + func = self.module2['make_class'] + self.assertEqual(func.args.format_args(), + 'any, base=data.module.YO, *args, **kwargs') + func = self.module['four_args'] + self.assertEqual(func.args.format_args(), 'a, b, c, d') + + def test_is_generator(self): + self.assertTrue(self.module2['generator'].is_generator()) + self.assertFalse(self.module2['not_a_generator'].is_generator()) + self.assertFalse(self.module2['make_class'].is_generator()) + + def test_is_abstract(self): + method = self.module2['AbstractClass']['to_override'] + self.assertTrue(method.is_abstract(pass_is_abstract=False)) + self.assertEqual(method.qname(), 'data.module2.AbstractClass.to_override') + self.assertEqual(method.pytype(), '%s.instancemethod' % BUILTINS) + method = self.module2['AbstractClass']['return_something'] + self.assertFalse(method.is_abstract(pass_is_abstract=False)) + # non regression : test raise "string" doesn't cause an exception in is_abstract + func = self.module2['raise_string'] + self.assertFalse(func.is_abstract(pass_is_abstract=False)) + + def test_is_abstract_decorated(self): + methods = test_utils.extract_node(""" + import abc + + class Klass(object): + @abc.abstractproperty + def prop(self): #@ + pass + + @abc.abstractmethod + def method1(self): #@ + pass + + some_other_decorator = lambda x: x + @some_other_decorator + def method2(self): #@ + pass + """) + self.assertTrue(methods[0].is_abstract(pass_is_abstract=False)) + self.assertTrue(methods[1].is_abstract(pass_is_abstract=False)) + self.assertFalse(methods[2].is_abstract(pass_is_abstract=False)) + +## def test_raises(self): +## method = self.module2['AbstractClass']['to_override'] +## self.assertEqual([str(term) for term in method.raises()], +## ["CallFunc(Name('NotImplementedError'), [], None, None)"] ) + +## def test_returns(self): +## method = self.module2['AbstractClass']['return_something'] +## # use string comp since Node doesn't handle __cmp__ +## self.assertEqual([str(term) for term in method.returns()], +## ["Const('toto')", "Const(None)"]) + + def test_lambda_pytype(self): + data = ''' + def f(): + g = lambda: None + ''' + astroid = test_utils.build_module(data) + g = list(astroid['f'].ilookup('g'))[0] + self.assertEqual(g.pytype(), '%s.function' % BUILTINS) + + def test_lambda_qname(self): + astroid = test_utils.build_module('lmbd = lambda: None', __name__) + self.assertEqual('%s.' % __name__, astroid['lmbd'].parent.value.qname()) + + def test_is_method(self): + data = ''' + class A: + def meth1(self): + return 1 + @classmethod + def meth2(cls): + return 2 + @staticmethod + def meth3(): + return 3 + + def function(): + return 0 + + @staticmethod + def sfunction(): + return -1 + ''' + astroid = test_utils.build_module(data) + self.assertTrue(astroid['A']['meth1'].is_method()) + self.assertTrue(astroid['A']['meth2'].is_method()) + self.assertTrue(astroid['A']['meth3'].is_method()) + self.assertFalse(astroid['function'].is_method()) + self.assertFalse(astroid['sfunction'].is_method()) + + def test_argnames(self): + if sys.version_info < (3, 0): + code = 'def f(a, (b, c), *args, **kwargs): pass' + else: + code = 'def f(a, b, c, *args, **kwargs): pass' + astroid = test_utils.build_module(code, __name__) + self.assertEqual(astroid['f'].argnames(), ['a', 'b', 'c', 'args', 'kwargs']) + + def test_return_nothing(self): + """test infered value on a function with empty return""" + data = ''' + def func(): + return + + a = func() + ''' + astroid = test_utils.build_module(data) + call = astroid.body[1].value + func_vals = call.infered() + self.assertEqual(len(func_vals), 1) + self.assertIsInstance(func_vals[0], nodes.Const) + self.assertIsNone(func_vals[0].value) + + def test_func_instance_attr(self): + """test instance attributes for functions""" + data = """ + def test(): + print(test.bar) + + test.bar = 1 + test() + """ + astroid = test_utils.build_module(data, 'mod') + func = astroid.body[2].value.func.infered()[0] + self.assertIsInstance(func, nodes.Function) + self.assertEqual(func.name, 'test') + one = func.getattr('bar')[0].infered()[0] + self.assertIsInstance(one, nodes.Const) + self.assertEqual(one.value, 1) + + def test_type_builtin_descriptor_subclasses(self): + astroid = test_utils.build_module(""" + class classonlymethod(classmethod): + pass + class staticonlymethod(staticmethod): + pass + + class Node: + @classonlymethod + def clsmethod_subclass(cls): + pass + @classmethod + def clsmethod(cls): + pass + @staticonlymethod + def staticmethod_subclass(cls): + pass + @staticmethod + def stcmethod(cls): + pass + """) + node = astroid.locals['Node'][0] + self.assertEqual(node.locals['clsmethod_subclass'][0].type, + 'classmethod') + self.assertEqual(node.locals['clsmethod'][0].type, + 'classmethod') + self.assertEqual(node.locals['staticmethod_subclass'][0].type, + 'staticmethod') + self.assertEqual(node.locals['stcmethod'][0].type, + 'staticmethod') + + def test_decorator_builtin_descriptors(self): + astroid = test_utils.build_module(""" + def static_decorator(platform=None, order=50): + def wrapper(f): + f.cgm_module = True + f.cgm_module_order = order + f.cgm_module_platform = platform + return staticmethod(f) + return wrapper + + def long_classmethod_decorator(platform=None, order=50): + def wrapper(f): + def wrapper2(f): + def wrapper3(f): + f.cgm_module = True + f.cgm_module_order = order + f.cgm_module_platform = platform + return classmethod(f) + return wrapper3(f) + return wrapper2(f) + return wrapper + + def classmethod_decorator(platform=None): + def wrapper(f): + f.platform = platform + return classmethod(f) + return wrapper + + def classmethod_wrapper(fn): + def wrapper(cls, *args, **kwargs): + result = fn(cls, *args, **kwargs) + return result + + return classmethod(wrapper) + + def staticmethod_wrapper(fn): + def wrapper(*args, **kwargs): + return fn(*args, **kwargs) + return staticmethod(wrapper) + + class SomeClass(object): + @static_decorator() + def static(node, cfg): + pass + @classmethod_decorator() + def classmethod(cls): + pass + @static_decorator + def not_so_static(node): + pass + @classmethod_decorator + def not_so_classmethod(node): + pass + @classmethod_wrapper + def classmethod_wrapped(cls): + pass + @staticmethod_wrapper + def staticmethod_wrapped(): + pass + @long_classmethod_decorator() + def long_classmethod(cls): + pass + """) + node = astroid.locals['SomeClass'][0] + self.assertEqual(node.locals['static'][0].type, + 'staticmethod') + self.assertEqual(node.locals['classmethod'][0].type, + 'classmethod') + self.assertEqual(node.locals['not_so_static'][0].type, + 'method') + self.assertEqual(node.locals['not_so_classmethod'][0].type, + 'method') + self.assertEqual(node.locals['classmethod_wrapped'][0].type, + 'classmethod') + self.assertEqual(node.locals['staticmethod_wrapped'][0].type, + 'staticmethod') + self.assertEqual(node.locals['long_classmethod'][0].type, + 'classmethod') + + +class ClassNodeTest(ModuleLoader, unittest.TestCase): + + def test_dict_interface(self): + _test_dict_interface(self, self.module['YOUPI'], 'method') + + def test_cls_special_attributes_1(self): + cls = self.module['YO'] + self.assertEqual(len(cls.getattr('__bases__')), 1) + self.assertEqual(len(cls.getattr('__name__')), 1) + self.assertIsInstance(cls.getattr('__name__')[0], nodes.Const) + self.assertEqual(cls.getattr('__name__')[0].value, 'YO') + self.assertEqual(len(cls.getattr('__doc__')), 1) + self.assertIsInstance(cls.getattr('__doc__')[0], nodes.Const) + self.assertEqual(cls.getattr('__doc__')[0].value, 'hehe') + self.assertEqual(len(cls.getattr('__module__')), 1) + self.assertIsInstance(cls.getattr('__module__')[0], nodes.Const) + self.assertEqual(cls.getattr('__module__')[0].value, 'data.module') + self.assertEqual(len(cls.getattr('__dict__')), 1) + if not cls.newstyle: + self.assertRaises(NotFoundError, cls.getattr, '__mro__') + for cls in (nodes.List._proxied, nodes.Const(1)._proxied): + self.assertEqual(len(cls.getattr('__bases__')), 1) + self.assertEqual(len(cls.getattr('__name__')), 1) + self.assertEqual(len(cls.getattr('__doc__')), 1, (cls, cls.getattr('__doc__'))) + self.assertEqual(cls.getattr('__doc__')[0].value, cls.doc) + self.assertEqual(len(cls.getattr('__module__')), 1) + self.assertEqual(len(cls.getattr('__dict__')), 1) + self.assertEqual(len(cls.getattr('__mro__')), 1) + + def test_cls_special_attributes_2(self): + astroid = test_utils.build_module(''' + class A: pass + class B: pass + + A.__bases__ += (B,) + ''', __name__) + self.assertEqual(len(astroid['A'].getattr('__bases__')), 2) + self.assertIsInstance(astroid['A'].getattr('__bases__')[0], nodes.Tuple) + self.assertIsInstance(astroid['A'].getattr('__bases__')[1], nodes.AssAttr) + + def test_instance_special_attributes(self): + for inst in (Instance(self.module['YO']), nodes.List(), nodes.Const(1)): + self.assertRaises(NotFoundError, inst.getattr, '__mro__') + self.assertRaises(NotFoundError, inst.getattr, '__bases__') + self.assertRaises(NotFoundError, inst.getattr, '__name__') + self.assertEqual(len(inst.getattr('__dict__')), 1) + self.assertEqual(len(inst.getattr('__doc__')), 1) + + def test_navigation(self): + klass = self.module['YO'] + self.assertEqual(klass.statement(), klass) + l_sibling = klass.previous_sibling() + self.assertTrue(isinstance(l_sibling, nodes.Function), l_sibling) + self.assertEqual(l_sibling.name, 'global_access') + r_sibling = klass.next_sibling() + self.assertIsInstance(r_sibling, nodes.Class) + self.assertEqual(r_sibling.name, 'YOUPI') + + def test_local_attr_ancestors(self): + klass2 = self.module['YOUPI'] + it = klass2.local_attr_ancestors('__init__') + anc_klass = next(it) + self.assertIsInstance(anc_klass, nodes.Class) + self.assertEqual(anc_klass.name, 'YO') + if sys.version_info[0] == 2: + self.assertRaises(StopIteration, partial(next, it)) + else: + anc_klass = next(it) + self.assertIsInstance(anc_klass, nodes.Class) + self.assertEqual(anc_klass.name, 'object') + self.assertRaises(StopIteration, partial(next, it)) + + it = klass2.local_attr_ancestors('method') + self.assertRaises(StopIteration, partial(next, it)) + + def test_instance_attr_ancestors(self): + klass2 = self.module['YOUPI'] + it = klass2.instance_attr_ancestors('yo') + anc_klass = next(it) + self.assertIsInstance(anc_klass, nodes.Class) + self.assertEqual(anc_klass.name, 'YO') + self.assertRaises(StopIteration, partial(next, it)) + klass2 = self.module['YOUPI'] + it = klass2.instance_attr_ancestors('member') + self.assertRaises(StopIteration, partial(next, it)) + + def test_methods(self): + expected_methods = {'__init__', 'class_method', 'method', 'static_method'} + klass2 = self.module['YOUPI'] + methods = {m.name for m in klass2.methods()} + self.assertTrue( + methods.issuperset(expected_methods)) + methods = {m.name for m in klass2.mymethods()} + self.assertSetEqual(expected_methods, methods) + klass2 = self.module2['Specialization'] + methods = {m.name for m in klass2.mymethods()} + self.assertSetEqual(set([]), methods) + method_locals = klass2.local_attr('method') + self.assertEqual(len(method_locals), 1) + self.assertEqual(method_locals[0].name, 'method') + self.assertRaises(NotFoundError, klass2.local_attr, 'nonexistant') + methods = {m.name for m in klass2.methods()} + self.assertTrue(methods.issuperset(expected_methods)) + + #def test_rhs(self): + # my_dict = self.module['MY_DICT'] + # self.assertIsInstance(my_dict.rhs(), nodes.Dict) + # a = self.module['YO']['a'] + # value = a.rhs() + # self.assertIsInstance(value, nodes.Const) + # self.assertEqual(value.value, 1) + + @unittest.skipIf(sys.version_info[0] >= 3, "Python 2 class semantics required.") + def test_ancestors(self): + klass = self.module['YOUPI'] + self.assertEqual(['YO'], [a.name for a in klass.ancestors()]) + klass = self.module2['Specialization'] + self.assertEqual(['YOUPI', 'YO'], [a.name for a in klass.ancestors()]) + + @unittest.skipIf(sys.version_info[0] < 3, "Python 3 class semantics required.") + def test_ancestors_py3(self): + klass = self.module['YOUPI'] + self.assertEqual(['YO', 'object'], [a.name for a in klass.ancestors()]) + klass = self.module2['Specialization'] + self.assertEqual(['YOUPI', 'YO', 'object'], [a.name for a in klass.ancestors()]) + + def test_type(self): + klass = self.module['YOUPI'] + self.assertEqual(klass.type, 'class') + klass = self.module2['Metaclass'] + self.assertEqual(klass.type, 'metaclass') + klass = self.module2['MyException'] + self.assertEqual(klass.type, 'exception') + klass = self.module2['MyIFace'] + self.assertEqual(klass.type, 'interface') + klass = self.module2['MyError'] + self.assertEqual(klass.type, 'exception') + # the following class used to be detected as a metaclass + # after the fix which used instance._proxied in .ancestors(), + # when in fact it is a normal class + klass = self.module2['NotMetaclass'] + self.assertEqual(klass.type, 'class') + + def test_interfaces(self): + for klass, interfaces in (('Concrete0', ['MyIFace']), + ('Concrete1', ['MyIFace', 'AnotherIFace']), + ('Concrete2', ['MyIFace', 'AnotherIFace']), + ('Concrete23', ['MyIFace', 'AnotherIFace'])): + klass = self.module2[klass] + self.assertEqual([i.name for i in klass.interfaces()], + interfaces) + + def test_concat_interfaces(self): + astroid = test_utils.build_module(''' + class IMachin: pass + + class Correct2: + """docstring""" + __implements__ = (IMachin,) + + class BadArgument: + """docstring""" + __implements__ = (IMachin,) + + class InterfaceCanNowBeFound: + """docstring""" + __implements__ = BadArgument.__implements__ + Correct2.__implements__ + ''') + self.assertEqual([i.name for i in astroid['InterfaceCanNowBeFound'].interfaces()], + ['IMachin']) + + def test_inner_classes(self): + eee = self.nonregr['Ccc']['Eee'] + self.assertEqual([n.name for n in eee.ancestors()], ['Ddd', 'Aaa', 'object']) + + + def test_classmethod_attributes(self): + data = ''' + class WebAppObject(object): + def registered(cls, application): + cls.appli = application + cls.schema = application.schema + cls.config = application.config + return cls + registered = classmethod(registered) + ''' + astroid = test_utils.build_module(data, __name__) + cls = astroid['WebAppObject'] + self.assertEqual(sorted(cls.locals.keys()), + ['appli', 'config', 'registered', 'schema']) + + + def test_class_getattr(self): + data = ''' + class WebAppObject(object): + appli = application + appli += 2 + del self.appli + ''' + astroid = test_utils.build_module(data, __name__) + cls = astroid['WebAppObject'] + # test del statement not returned by getattr + self.assertEqual(len(cls.getattr('appli')), 2) + + + def test_instance_getattr(self): + data = ''' + class WebAppObject(object): + def __init__(self, application): + self.appli = application + self.appli += 2 + del self.appli + ''' + astroid = test_utils.build_module(data) + inst = Instance(astroid['WebAppObject']) + # test del statement not returned by getattr + self.assertEqual(len(inst.getattr('appli')), 2) + + + def test_instance_getattr_with_class_attr(self): + data = ''' + class Parent: + aa = 1 + cc = 1 + + class Klass(Parent): + aa = 0 + bb = 0 + + def incr(self, val): + self.cc = self.aa + if val > self.aa: + val = self.aa + if val < self.bb: + val = self.bb + self.aa += val + ''' + astroid = test_utils.build_module(data) + inst = Instance(astroid['Klass']) + self.assertEqual(len(inst.getattr('aa')), 3, inst.getattr('aa')) + self.assertEqual(len(inst.getattr('bb')), 1, inst.getattr('bb')) + self.assertEqual(len(inst.getattr('cc')), 2, inst.getattr('cc')) + + + def test_getattr_method_transform(self): + data = ''' + class Clazz(object): + + def m1(self, value): + self.value = value + m2 = m1 + + def func(arg1, arg2): + "function that will be used as a method" + return arg1.value + arg2 + + Clazz.m3 = func + inst = Clazz() + inst.m4 = func + ''' + astroid = test_utils.build_module(data) + cls = astroid['Clazz'] + # test del statement not returned by getattr + for method in ('m1', 'm2', 'm3'): + inferred = list(cls.igetattr(method)) + self.assertEqual(len(inferred), 1) + self.assertIsInstance(inferred[0], UnboundMethod) + inferred = list(Instance(cls).igetattr(method)) + self.assertEqual(len(inferred), 1) + self.assertIsInstance(inferred[0], BoundMethod) + inferred = list(Instance(cls).igetattr('m4')) + self.assertEqual(len(inferred), 1) + self.assertIsInstance(inferred[0], nodes.Function) + + def test_getattr_from_grandpa(self): + data = ''' + class Future: + attr = 1 + + class Present(Future): + pass + + class Past(Present): + pass + ''' + astroid = test_utils.build_module(data) + past = astroid['Past'] + attr = past.getattr('attr') + self.assertEqual(len(attr), 1) + attr1 = attr[0] + self.assertIsInstance(attr1, nodes.AssName) + self.assertEqual(attr1.name, 'attr') + + def test_function_with_decorator_lineno(self): + data = ''' + @f(a=2, + b=3) + def g1(x): + print(x) + + @f(a=2, + b=3) + def g2(): + pass + ''' + astroid = test_utils.build_module(data) + self.assertEqual(astroid['g1'].fromlineno, 4) + self.assertEqual(astroid['g1'].tolineno, 5) + self.assertEqual(astroid['g2'].fromlineno, 9) + self.assertEqual(astroid['g2'].tolineno, 10) + + @test_utils.require_version(maxver='3.0') + def test_simple_metaclass(self): + astroid = test_utils.build_module(""" + class Test(object): + __metaclass__ = type + """) + klass = astroid['Test'] + metaclass = klass.metaclass() + self.assertIsInstance(metaclass, scoped_nodes.Class) + self.assertEqual(metaclass.name, 'type') + + def test_metaclass_error(self): + astroid = test_utils.build_module(""" + class Test(object): + __metaclass__ = typ + """) + klass = astroid['Test'] + self.assertFalse(klass.metaclass()) + + @test_utils.require_version(maxver='3.0') + def test_metaclass_imported(self): + astroid = test_utils.build_module(""" + from abc import ABCMeta + class Test(object): + __metaclass__ = ABCMeta + """) + klass = astroid['Test'] + + metaclass = klass.metaclass() + self.assertIsInstance(metaclass, scoped_nodes.Class) + self.assertEqual(metaclass.name, 'ABCMeta') + + def test_metaclass_yes_leak(self): + astroid = test_utils.build_module(""" + # notice `ab` instead of `abc` + from ab import ABCMeta + + class Meta(object): + __metaclass__ = ABCMeta + """) + klass = astroid['Meta'] + self.assertIsNone(klass.metaclass()) + + @test_utils.require_version(maxver='3.0') + def test_newstyle_and_metaclass_good(self): + astroid = test_utils.build_module(""" + from abc import ABCMeta + class Test: + __metaclass__ = ABCMeta + """) + klass = astroid['Test'] + self.assertTrue(klass.newstyle) + self.assertEqual(klass.metaclass().name, 'ABCMeta') + astroid = test_utils.build_module(""" + from abc import ABCMeta + __metaclass__ = ABCMeta + class Test: + pass + """) + klass = astroid['Test'] + self.assertTrue(klass.newstyle) + self.assertEqual(klass.metaclass().name, 'ABCMeta') + + @test_utils.require_version(maxver='3.0') + def test_nested_metaclass(self): + astroid = test_utils.build_module(""" + from abc import ABCMeta + class A(object): + __metaclass__ = ABCMeta + class B: pass + + __metaclass__ = ABCMeta + class C: + __metaclass__ = type + class D: pass + """) + a = astroid['A'] + b = a.locals['B'][0] + c = astroid['C'] + d = c.locals['D'][0] + self.assertEqual(a.metaclass().name, 'ABCMeta') + self.assertFalse(b.newstyle) + self.assertIsNone(b.metaclass()) + self.assertEqual(c.metaclass().name, 'type') + self.assertEqual(d.metaclass().name, 'ABCMeta') + + @test_utils.require_version(maxver='3.0') + def test_parent_metaclass(self): + astroid = test_utils.build_module(""" + from abc import ABCMeta + class Test: + __metaclass__ = ABCMeta + class SubTest(Test): pass + """) + klass = astroid['SubTest'] + self.assertTrue(klass.newstyle) + metaclass = klass.metaclass() + self.assertIsInstance(metaclass, scoped_nodes.Class) + self.assertEqual(metaclass.name, 'ABCMeta') + + @test_utils.require_version(maxver='3.0') + def test_metaclass_ancestors(self): + astroid = test_utils.build_module(""" + from abc import ABCMeta + + class FirstMeta(object): + __metaclass__ = ABCMeta + + class SecondMeta(object): + __metaclass__ = type + + class Simple(object): + pass + + class FirstImpl(FirstMeta): pass + class SecondImpl(FirstImpl): pass + class ThirdImpl(Simple, SecondMeta): + pass + """) + classes = { + 'ABCMeta': ('FirstImpl', 'SecondImpl'), + 'type': ('ThirdImpl', ) + } + for metaclass, names in classes.items(): + for name in names: + impl = astroid[name] + meta = impl.metaclass() + self.assertIsInstance(meta, nodes.Class) + self.assertEqual(meta.name, metaclass) + + def test_metaclass_type(self): + klass = test_utils.extract_node(""" + def with_metaclass(meta, base=object): + return meta("NewBase", (base, ), {}) + + class ClassWithMeta(with_metaclass(type)): #@ + pass + """) + self.assertEqual( + ['NewBase', 'object'], + [base.name for base in klass.ancestors()]) + + def test_metaclass_generator_hack(self): + klass = test_utils.extract_node(""" + import six + + class WithMeta(six.with_metaclass(type, object)): #@ + pass + """) + self.assertEqual( + ['object'], + [base.name for base in klass.ancestors()]) + self.assertEqual( + 'type', klass.metaclass().name) + + def test_nonregr_infer_callresult(self): + astroid = test_utils.build_module(""" + class Delegate(object): + def __get__(self, obj, cls): + return getattr(obj._subject, self.attribute) + + class CompositeBuilder(object): + __call__ = Delegate() + + builder = CompositeBuilder(result, composite) + tgts = builder() + """) + instance = astroid['tgts'] + # used to raise "'_Yes' object is not iterable", see + # https://bitbucket.org/logilab/astroid/issue/17 + self.assertEqual(list(instance.infer()), [YES]) + + def test_slots(self): + astroid = test_utils.build_module(""" + from collections import deque + from textwrap import dedent + + class First(object): + __slots__ = ("a", "b", 1) + class Second(object): + __slots__ = "a" + class Third(object): + __slots__ = deque(["a", "b", "c"]) + class Fourth(object): + __slots__ = {"a": "a", "b": "b"} + class Fifth(object): + __slots__ = list + class Sixth(object): + __slots__ = "" + class Seventh(object): + __slots__ = dedent.__name__ + class Eight(object): + __slots__ = ("parens") + class Ninth(object): + pass + class Ten(object): + __slots__ = dict({"a": "b", "c": "d"}) + """) + first = astroid['First'] + first_slots = first.slots() + self.assertEqual(len(first_slots), 2) + self.assertIsInstance(first_slots[0], nodes.Const) + self.assertIsInstance(first_slots[1], nodes.Const) + self.assertEqual(first_slots[0].value, "a") + self.assertEqual(first_slots[1].value, "b") + + second_slots = astroid['Second'].slots() + self.assertEqual(len(second_slots), 1) + self.assertIsInstance(second_slots[0], nodes.Const) + self.assertEqual(second_slots[0].value, "a") + + third_slots = astroid['Third'].slots() + self.assertIsNone(third_slots) + + fourth_slots = astroid['Fourth'].slots() + self.assertEqual(len(fourth_slots), 2) + self.assertIsInstance(fourth_slots[0], nodes.Const) + self.assertIsInstance(fourth_slots[1], nodes.Const) + self.assertEqual(fourth_slots[0].value, "a") + self.assertEqual(fourth_slots[1].value, "b") + + fifth_slots = astroid['Fifth'].slots() + self.assertIsNone(fifth_slots) + + sixth_slots = astroid['Sixth'].slots() + self.assertIsNone(sixth_slots) + + seventh_slots = astroid['Seventh'].slots() + self.assertIsNone(seventh_slots) + + eight_slots = astroid['Eight'].slots() + self.assertEqual(len(eight_slots), 1) + self.assertIsInstance(eight_slots[0], nodes.Const) + self.assertEqual(eight_slots[0].value, "parens") + + self.assertIsNone(astroid['Ninth'].slots()) + + tenth_slots = astroid['Ten'].slots() + self.assertEqual(len(tenth_slots), 2) + self.assertEqual( + [slot.value for slot in tenth_slots], + ["a", "c"]) + + @test_utils.require_version(maxver='3.0') + def test_slots_py2(self): + module = test_utils.build_module(""" + class UnicodeSlots(object): + __slots__ = (u"a", u"b", "c") + """) + slots = module['UnicodeSlots'].slots() + self.assertEqual(len(slots), 3) + self.assertEqual(slots[0].value, "a") + self.assertEqual(slots[1].value, "b") + self.assertEqual(slots[2].value, "c") + + @test_utils.require_version(maxver='3.0') + def test_slots_py2_not_implemented(self): + module = test_utils.build_module(""" + class OldStyle: + __slots__ = ("a", "b") + """) + msg = "The concept of slots is undefined for old-style classes." + with self.assertRaises(NotImplementedError) as cm: + module['OldStyle'].slots() + self.assertEqual(str(cm.exception), msg) + + def assertEqualMro(self, klass, expected_mro): + self.assertEqual( + [member.name for member in klass.mro()], + expected_mro) + + @test_utils.require_version(maxver='3.0') + def test_no_mro_for_old_style(self): + node = test_utils.extract_node(""" + class Old: pass""") + with self.assertRaises(NotImplementedError) as cm: + node.mro() + self.assertEqual(str(cm.exception), "Could not obtain mro for " + "old-style classes.") + + def test_mro(self): + astroid = test_utils.build_module(""" + class C(object): pass + class D(dict, C): pass + + class A1(object): pass + class B1(A1): pass + class C1(A1): pass + class D1(B1, C1): pass + class E1(C1, B1): pass + class F1(D1, E1): pass + class G1(E1, D1): pass + + class Boat(object): pass + class DayBoat(Boat): pass + class WheelBoat(Boat): pass + class EngineLess(DayBoat): pass + class SmallMultihull(DayBoat): pass + class PedalWheelBoat(EngineLess, WheelBoat): pass + class SmallCatamaran(SmallMultihull): pass + class Pedalo(PedalWheelBoat, SmallCatamaran): pass + + class OuterA(object): + class Inner(object): + pass + class OuterB(OuterA): + class Inner(OuterA.Inner): + pass + class OuterC(OuterA): + class Inner(OuterA.Inner): + pass + class OuterD(OuterC): + class Inner(OuterC.Inner, OuterB.Inner): + pass + + """) + self.assertEqualMro(astroid['D'], ['D', 'dict', 'C', 'object']) + self.assertEqualMro(astroid['D1'], ['D1', 'B1', 'C1', 'A1', 'object']) + self.assertEqualMro(astroid['E1'], ['E1', 'C1', 'B1', 'A1', 'object']) + with self.assertRaises(ResolveError) as cm: + astroid['F1'].mro() + self.assertEqual(str(cm.exception), + "Cannot create a consistent method resolution order " + "for bases (B1, C1, A1, object), " + "(C1, B1, A1, object)") + + with self.assertRaises(ResolveError) as cm: + astroid['G1'].mro() + self.assertEqual(str(cm.exception), + "Cannot create a consistent method resolution order " + "for bases (C1, B1, A1, object), " + "(B1, C1, A1, object)") + + self.assertEqualMro( + astroid['PedalWheelBoat'], + ["PedalWheelBoat", "EngineLess", + "DayBoat", "WheelBoat", "Boat", "object"]) + + self.assertEqualMro( + astroid["SmallCatamaran"], + ["SmallCatamaran", "SmallMultihull", "DayBoat", "Boat", "object"]) + + self.assertEqualMro( + astroid["Pedalo"], + ["Pedalo", "PedalWheelBoat", "EngineLess", "SmallCatamaran", + "SmallMultihull", "DayBoat", "WheelBoat", "Boat", "object"]) + + self.assertEqualMro( + astroid['OuterD']['Inner'], + ['Inner', 'Inner', 'Inner', 'Inner', 'object']) + + +if __name__ == '__main__': + unittest.main() diff -Nru astroid-1.0.1/astroid/tests/unittest_utils.py astroid-1.3.8/astroid/tests/unittest_utils.py --- astroid-1.0.1/astroid/tests/unittest_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/tests/unittest_utils.py 2015-03-09 22:00:27.000000000 +0000 @@ -0,0 +1,102 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +import unittest + +from astroid import builder, nodes +from astroid.node_classes import are_exclusive + +builder = builder.AstroidBuilder() + +class AreExclusiveTC(unittest.TestCase): + def test_not_exclusive(self): + astroid = builder.string_build(""" +x = 10 +for x in range(5): + print (x) + +if x > 0: + print ('#' * x) + """, __name__, __file__) + xass1 = astroid.locals['x'][0] + assert xass1.lineno == 2 + xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'x'] + assert len(xnames) == 3 + assert xnames[1].lineno == 6 + self.assertEqual(are_exclusive(xass1, xnames[1]), False) + self.assertEqual(are_exclusive(xass1, xnames[2]), False) + + def test_if(self): + astroid = builder.string_build(''' + +if 1: + a = 1 + a = 2 +elif 2: + a = 12 + a = 13 +else: + a = 3 + a = 4 + ''') + a1 = astroid.locals['a'][0] + a2 = astroid.locals['a'][1] + a3 = astroid.locals['a'][2] + a4 = astroid.locals['a'][3] + a5 = astroid.locals['a'][4] + a6 = astroid.locals['a'][5] + self.assertEqual(are_exclusive(a1, a2), False) + self.assertEqual(are_exclusive(a1, a3), True) + self.assertEqual(are_exclusive(a1, a5), True) + self.assertEqual(are_exclusive(a3, a5), True) + self.assertEqual(are_exclusive(a3, a4), False) + self.assertEqual(are_exclusive(a5, a6), False) + + def test_try_except(self): + astroid = builder.string_build(''' +try: + def exclusive_func2(): + "docstring" +except TypeError: + def exclusive_func2(): + "docstring" +except: + def exclusive_func2(): + "docstring" +else: + def exclusive_func2(): + "this one redefine the one defined line 42" + + ''') + f1 = astroid.locals['exclusive_func2'][0] + f2 = astroid.locals['exclusive_func2'][1] + f3 = astroid.locals['exclusive_func2'][2] + f4 = astroid.locals['exclusive_func2'][3] + self.assertEqual(are_exclusive(f1, f2), True) + self.assertEqual(are_exclusive(f1, f3), True) + self.assertEqual(are_exclusive(f1, f4), False) + self.assertEqual(are_exclusive(f2, f4), True) + self.assertEqual(are_exclusive(f3, f4), True) + self.assertEqual(are_exclusive(f3, f2), True) + + self.assertEqual(are_exclusive(f2, f1), True) + self.assertEqual(are_exclusive(f4, f1), False) + self.assertEqual(are_exclusive(f4, f2), True) + +if __name__ == '__main__': + unittest.main() + diff -Nru astroid-1.0.1/astroid/test_utils.py astroid-1.3.8/astroid/test_utils.py --- astroid-1.0.1/astroid/test_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/test_utils.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,218 @@ +"""Utility functions for test code that uses astroid ASTs as input.""" +import functools +import sys +import textwrap + +from astroid import nodes +from astroid import builder +# The name of the transient function that is used to +# wrap expressions to be extracted when calling +# extract_node. +_TRANSIENT_FUNCTION = '__' + +# The comment used to select a statement to be extracted +# when calling extract_node. +_STATEMENT_SELECTOR = '#@' + + +def _extract_expressions(node): + """Find expressions in a call to _TRANSIENT_FUNCTION and extract them. + + The function walks the AST recursively to search for expressions that + are wrapped into a call to _TRANSIENT_FUNCTION. If it finds such an + expression, it completely removes the function call node from the tree, + replacing it by the wrapped expression inside the parent. + + :param node: An astroid node. + :type node: astroid.bases.NodeNG + :yields: The sequence of wrapped expressions on the modified tree + expression can be found. + """ + if (isinstance(node, nodes.CallFunc) + and isinstance(node.func, nodes.Name) + and node.func.name == _TRANSIENT_FUNCTION): + real_expr = node.args[0] + real_expr.parent = node.parent + # Search for node in all _astng_fields (the fields checked when + # get_children is called) of its parent. Some of those fields may + # be lists or tuples, in which case the elements need to be checked. + # When we find it, replace it by real_expr, so that the AST looks + # like no call to _TRANSIENT_FUNCTION ever took place. + for name in node.parent._astroid_fields: + child = getattr(node.parent, name) + if isinstance(child, (list, tuple)): + for idx, compound_child in enumerate(child): + if compound_child is node: + child[idx] = real_expr + elif child is node: + setattr(node.parent, name, real_expr) + yield real_expr + else: + for child in node.get_children(): + for result in _extract_expressions(child): + yield result + + +def _find_statement_by_line(node, line): + """Extracts the statement on a specific line from an AST. + + If the line number of node matches line, it will be returned; + otherwise its children are iterated and the function is called + recursively. + + :param node: An astroid node. + :type node: astroid.bases.NodeNG + :param line: The line number of the statement to extract. + :type line: int + :returns: The statement on the line, or None if no statement for the line + can be found. + :rtype: astroid.bases.NodeNG or None + """ + if isinstance(node, (nodes.Class, nodes.Function)): + # This is an inaccuracy in the AST: the nodes that can be + # decorated do not carry explicit information on which line + # the actual definition (class/def), but .fromline seems to + # be close enough. + node_line = node.fromlineno + else: + node_line = node.lineno + + if node_line == line: + return node + + for child in node.get_children(): + result = _find_statement_by_line(child, line) + if result: + return result + + return None + +def extract_node(code, module_name=''): + """Parses some Python code as a module and extracts a designated AST node. + + Statements: + To extract one or more statement nodes, append #@ to the end of the line + + Examples: + >>> def x(): + >>> def y(): + >>> return 1 #@ + + The return statement will be extracted. + + >>> class X(object): + >>> def meth(self): #@ + >>> pass + + The funcion object 'meth' will be extracted. + + Expressions: + To extract arbitrary expressions, surround them with the fake + function call __(...). After parsing, the surrounded expression + will be returned and the whole AST (accessible via the returned + node's parent attribute) will look like the function call was + never there in the first place. + + Examples: + >>> a = __(1) + + The const node will be extracted. + + >>> def x(d=__(foo.bar)): pass + + The node containing the default argument will be extracted. + + >>> def foo(a, b): + >>> return 0 < __(len(a)) < b + + The node containing the function call 'len' will be extracted. + + If no statements or expressions are selected, the last toplevel + statement will be returned. + + If the selected statement is a discard statement, (i.e. an expression + turned into a statement), the wrapped expression is returned instead. + + For convenience, singleton lists are unpacked. + + :param str code: A piece of Python code that is parsed as + a module. Will be passed through textwrap.dedent first. + :param str module_name: The name of the module. + :returns: The designated node from the parse tree, or a list of nodes. + :rtype: astroid.bases.NodeNG, or a list of nodes. + """ + def _extract(node): + if isinstance(node, nodes.Discard): + return node.value + else: + return node + + requested_lines = [] + for idx, line in enumerate(code.splitlines()): + if line.strip().endswith(_STATEMENT_SELECTOR): + requested_lines.append(idx + 1) + + tree = build_module(code, module_name=module_name) + extracted = [] + if requested_lines: + for line in requested_lines: + extracted.append(_find_statement_by_line(tree, line)) + + # Modifies the tree. + extracted.extend(_extract_expressions(tree)) + + if not extracted: + extracted.append(tree.body[-1]) + + extracted = [_extract(node) for node in extracted] + if len(extracted) == 1: + return extracted[0] + else: + return extracted + + +def build_module(code, module_name='', path=None): + """Parses a string module with a builder. + :param code: The code for the module. + :type code: str + :param module_name: The name for the module + :type module_name: str + :param path: The path for the module + :type module_name: str + :returns: The module AST. + :rtype: astroid.bases.NodeNG + """ + code = textwrap.dedent(code) + return builder.AstroidBuilder(None).string_build(code, modname=module_name, path=path) + + +def require_version(minver=None, maxver=None): + """ Compare version of python interpreter to the given one. Skip the test + if older. + """ + def parse(string, default=None): + string = string or default + try: + return tuple(int(v) for v in string.split('.')) + except ValueError: + raise ValueError('%s is not a correct version : should be X.Y[.Z].' % version) + + def check_require_version(f): + current = sys.version_info[:3] + if parse(minver, "0") < current <= parse(maxver, "4"): + return f + else: + str_version = '.'.join(str(v) for v in sys.version_info) + @functools.wraps(f) + def new_f(self, *args, **kwargs): + if minver is not None: + self.skipTest('Needs Python > %s. Current version is %s.' % (minver, str_version)) + elif maxver is not None: + self.skipTest('Needs Python <= %s. Current version is %s.' % (maxver, str_version)) + return new_f + + + return check_require_version + +def get_name_node(start_from, name, index=0): + return [n for n in start_from.nodes_of_class(nodes.Name) if n.name == name][index] diff -Nru astroid-1.0.1/astroid/utils.py astroid-1.3.8/astroid/utils.py --- astroid-1.0.1/astroid/utils.py 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/astroid/utils.py 2015-08-02 18:37:18.000000000 +0000 @@ -0,0 +1,239 @@ +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . +"""this module contains some utilities to navigate in the tree or to +extract information from it +""" +from __future__ import print_function + +__docformat__ = "restructuredtext en" + +from astroid.exceptions import AstroidBuildingException +from astroid.builder import parse + + +class ASTWalker(object): + """a walker visiting a tree in preorder, calling on the handler: + + * visit_ on entering a node, where class name is the class of + the node in lower case + + * leave_ on leaving a node, where class name is the class of + the node in lower case + """ + + def __init__(self, handler): + self.handler = handler + self._cache = {} + + def walk(self, node, _done=None): + """walk on the tree from , getting callbacks from handler""" + if _done is None: + _done = set() + if node in _done: + raise AssertionError((id(node), node, node.parent)) + _done.add(node) + self.visit(node) + for child_node in node.get_children(): + self.handler.set_context(node, child_node) + assert child_node is not node + self.walk(child_node, _done) + self.leave(node) + assert node.parent is not node + + def get_callbacks(self, node): + """get callbacks from handler for the visited node""" + klass = node.__class__ + methods = self._cache.get(klass) + if methods is None: + handler = self.handler + kid = klass.__name__.lower() + e_method = getattr(handler, 'visit_%s' % kid, + getattr(handler, 'visit_default', None)) + l_method = getattr(handler, 'leave_%s' % kid, + getattr(handler, 'leave_default', None)) + self._cache[klass] = (e_method, l_method) + else: + e_method, l_method = methods + return e_method, l_method + + def visit(self, node): + """walk on the tree from , getting callbacks from handler""" + method = self.get_callbacks(node)[0] + if method is not None: + method(node) + + def leave(self, node): + """walk on the tree from , getting callbacks from handler""" + method = self.get_callbacks(node)[1] + if method is not None: + method(node) + + +class LocalsVisitor(ASTWalker): + """visit a project by traversing the locals dictionary""" + def __init__(self): + ASTWalker.__init__(self, self) + self._visited = {} + + def visit(self, node): + """launch the visit starting from the given node""" + if node in self._visited: + return + self._visited[node] = 1 # FIXME: use set ? + methods = self.get_callbacks(node) + if methods[0] is not None: + methods[0](node) + if 'locals' in node.__dict__: # skip Instance and other proxy + for local_node in node.values(): + self.visit(local_node) + if methods[1] is not None: + return methods[1](node) + + +def _check_children(node): + """a helper function to check children - parent relations""" + for child in node.get_children(): + ok = False + if child is None: + print("Hm, child of %s is None" % node) + continue + if not hasattr(child, 'parent'): + print(" ERROR: %s has child %s %x with no parent" % ( + node, child, id(child))) + elif not child.parent: + print(" ERROR: %s has child %s %x with parent %r" % ( + node, child, id(child), child.parent)) + elif child.parent is not node: + print(" ERROR: %s %x has child %s %x with wrong parent %s" % ( + node, id(node), child, id(child), child.parent)) + else: + ok = True + if not ok: + print("lines;", node.lineno, child.lineno) + print("of module", node.root(), node.root().name) + raise AstroidBuildingException + _check_children(child) + + +class TreeTester(object): + '''A helper class to see _ast tree and compare with astroid tree + + indent: string for tree indent representation + lineno: bool to tell if we should print the line numbers + + >>> tester = TreeTester('print') + >>> print tester.native_tree_repr() + + + . body = [ + . + . . nl = True + . ] + >>> print tester.astroid_tree_repr() + Module() + body = [ + Print() + dest = + values = [ + ] + ] + ''' + + indent = '. ' + lineno = False + + def __init__(self, sourcecode): + self._string = '' + self.sourcecode = sourcecode + self._ast_node = None + self.build_ast() + + def build_ast(self): + """build the _ast tree from the source code""" + self._ast_node = parse(self.sourcecode) + + def native_tree_repr(self, node=None, indent=''): + """get a nice representation of the _ast tree""" + self._string = '' + if node is None: + node = self._ast_node + self._native_repr_tree(node, indent) + return self._string + + + def _native_repr_tree(self, node, indent, _done=None): + """recursive method for the native tree representation""" + from _ast import Load as _Load, Store as _Store, Del as _Del + from _ast import AST as Node + if _done is None: + _done = set() + if node in _done: + self._string += '\nloop in tree: %r (%s)' % ( + node, getattr(node, 'lineno', None)) + return + _done.add(node) + self._string += '\n' + indent + '<%s>' % node.__class__.__name__ + indent += self.indent + if not hasattr(node, '__dict__'): + self._string += '\n' + self.indent + " ** node has no __dict__ " + str(node) + return + node_dict = node.__dict__ + if hasattr(node, '_attributes'): + for a in node._attributes: + attr = node_dict[a] + if attr is None: + continue + if a in ("lineno", "col_offset") and not self.lineno: + continue + self._string += '\n' + indent + a + " = " + repr(attr) + for field in node._fields or (): + attr = node_dict[field] + if attr is None: + continue + if isinstance(attr, list): + if not attr: + continue + self._string += '\n' + indent + field + ' = [' + for elt in attr: + self._native_repr_tree(elt, indent, _done) + self._string += '\n' + indent + ']' + continue + if isinstance(attr, (_Load, _Store, _Del)): + continue + if isinstance(attr, Node): + self._string += '\n' + indent + field + " = " + self._native_repr_tree(attr, indent, _done) + else: + self._string += '\n' + indent + field + " = " + repr(attr) + + + def build_astroid_tree(self): + """build astroid tree from the _ast tree + """ + from astroid.builder import AstroidBuilder + tree = AstroidBuilder().string_build(self.sourcecode) + return tree + + def astroid_tree_repr(self, ids=False): + """build the astroid tree and return a nice tree representation""" + mod = self.build_astroid_tree() + return mod.repr_tree(ids) + + +__all__ = ('LocalsVisitor', 'ASTWalker',) + diff -Nru astroid-1.0.1/astroid.egg-info/PKG-INFO astroid-1.3.8/astroid.egg-info/PKG-INFO --- astroid-1.0.1/astroid.egg-info/PKG-INFO 2013-10-18 15:34:18.000000000 +0000 +++ astroid-1.3.8/astroid.egg-info/PKG-INFO 2015-08-02 20:40:00.000000000 +0000 @@ -1,71 +1,80 @@ -Metadata-Version: 1.1 -Name: astroid -Version: 1.0.1 -Summary: rebuild a new abstract syntax tree from Python's ast -Home-page: http://bitbucket.org/logilab/astroid -Author: Logilab -Author-email: python-projects@lists.logilab.org -License: LGPL -Description: Astroid - ======= - - What's this? - ------------ - - The aim of this module is to provide a common base representation of - python source code for projects such as pychecker, pyreverse, - pylint... Well, actually the development of this library is essentially - governed by pylint's needs. It used to be called logilab-astng. - - It provides a compatible representation which comes from the `_ast` - module. It rebuilds the tree generated by the builtin _ast module by - recursively walking down the AST and building an extended ast. The new - node classes have additional methods and attributes for different - usages. They include some support for static inference and local name - scopes. Furthermore, astroid builds partial trees by inspecting living - objects. - - Main modules are: - - * `bases`, `node_classses` and `scoped_nodes` contain the classes for the - different type of nodes of the tree. - - * the `manager` contains a high level object to get astroid trees from - source files and living objects. It maintains a cache of previously - constructed tree for quick access. - - - Installation - ------------ - - Extract the tarball, jump into the created directory and run:: - - python setup.py install - - For installation options, see:: - - python setup.py install --help - - - If you have any questions, please mail the code-quality@python.org - mailing list for support. See - http://mail.python.org/mailman/listinfo/code-quality for subscription - information and archives. You may find older archives at - http://lists.logilab.org/mailman/listinfo/python-projects . - - Test - ---- - - Tests are in the 'test' subdirectory. To launch the whole tests suite - at once, you may use the 'pytest' utility from logilab-common (simply - type 'pytest' from within this directory) or if you're running python - >= 2.7, using discover, for instance:: - - python -m unittest discover -p "unittest*.py" - -Platform: UNKNOWN -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Quality Assurance -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 +Metadata-Version: 1.1 +Name: astroid +Version: 1.3.8 +Summary: A abstract syntax tree for Python with inference support. +Home-page: http://bitbucket.org/logilab/astroid +Author: Logilab +Author-email: pylint-dev@lists.logilab.org +License: LGPL +Description: .. image:: https://drone.io/bitbucket.org/logilab/astroid/status.png + :alt: drone.io Build Status + :target: https://drone.io/bitbucket.org/logilab/astroid + + Astroid + ======= + + What's this? + ------------ + + The aim of this module is to provide a common base representation of + python source code for projects such as pychecker, pyreverse, + pylint... Well, actually the development of this library is essentially + governed by pylint's needs. It used to be called logilab-astng. + + It provides a compatible representation which comes from the `_ast` + module. It rebuilds the tree generated by the builtin _ast module by + recursively walking down the AST and building an extended ast. The new + node classes have additional methods and attributes for different + usages. They include some support for static inference and local name + scopes. Furthermore, astroid builds partial trees by inspecting living + objects. + + Main modules are: + + * `bases`, `node_classses` and `scoped_nodes` contain the classes for the + different type of nodes of the tree. + + * the `manager` contains a high level object to get astroid trees from + source files and living objects. It maintains a cache of previously + constructed tree for quick access. + + + Installation + ------------ + + Extract the tarball, jump into the created directory and run:: + + python setup.py install + + For installation options, see:: + + python setup.py install --help + + + If you have any questions, please mail the code-quality@python.org + mailing list for support. See + http://mail.python.org/mailman/listinfo/code-quality for subscription + information and archives. You may find older archives at + http://lists.logilab.org/mailman/listinfo/python-projects . + + Python Versions + --------------- + + astroid is compatible with Python 2.7 as well as 3.3 and later. astroid uses + the same code base for both Python versions, using six. + + Test + ---- + + Tests are in the 'test' subdirectory. To launch the whole tests suite + at once, you may use the 'pytest' utility from logilab-common (simply + type 'pytest' from within this directory) or using unittest discover:: + + python -m unittest discover -p "unittest*.py" + +Platform: UNKNOWN +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 diff -Nru astroid-1.0.1/astroid.egg-info/requires.txt astroid-1.3.8/astroid.egg-info/requires.txt --- astroid-1.0.1/astroid.egg-info/requires.txt 2013-10-18 15:34:18.000000000 +0000 +++ astroid-1.3.8/astroid.egg-info/requires.txt 2015-08-02 20:40:00.000000000 +0000 @@ -1 +1,2 @@ -logilab-common >= 0.60.0 \ No newline at end of file +logilab-common>=0.63.0 +six diff -Nru astroid-1.0.1/astroid.egg-info/SOURCES.txt astroid-1.3.8/astroid.egg-info/SOURCES.txt --- astroid-1.0.1/astroid.egg-info/SOURCES.txt 2013-10-18 15:34:18.000000000 +0000 +++ astroid-1.3.8/astroid.egg-info/SOURCES.txt 2015-08-02 20:40:00.000000000 +0000 @@ -3,90 +3,138 @@ ChangeLog MANIFEST.in README -README.Python3 +setup.cfg setup.py -./__init__.py -./__pkginfo__.py -./as_string.py -./bases.py -./builder.py -./exceptions.py -./inference.py -./inspector.py -./manager.py -./mixins.py -./node_classes.py -./nodes.py -./protocols.py -./raw_building.py -./rebuilder.py -./scoped_nodes.py -./test_utils.py -./utils.py -./test/unittest_brain.py -./test/unittest_builder.py -./test/unittest_inference.py -./test/unittest_inspector.py -./test/unittest_lookup.py -./test/unittest_manager.py -./test/unittest_nodes.py -./test/unittest_python3.py -./test/unittest_regrtest.py -./test/unittest_scoped_nodes.py -./test/unittest_utils.py -./test/data/__init__.py -./test/data/absimport.py -./test/data/all.py -./test/data/email.py -./test/data/format.py -./test/data/module.py -./test/data/module2.py -./test/data/noendingnewline.py -./test/data/nonregr.py -./test/data/notall.py -./test/data/SSL1/Connection1.py -./test/data/SSL1/__init__.py -./test/data/appl/__init__.py -./test/data/appl/myConnection.py -./test/data2/__init__.py -./test/data2/clientmodule_test.py -./test/data2/suppliermodule_test.py +tox.ini +astroid/__init__.py +astroid/__pkginfo__.py +astroid/as_string.py +astroid/astpeephole.py +astroid/bases.py +astroid/builder.py +astroid/exceptions.py +astroid/inference.py +astroid/inspector.py +astroid/manager.py +astroid/mixins.py +astroid/modutils.py +astroid/node_classes.py +astroid/nodes.py +astroid/protocols.py +astroid/raw_building.py +astroid/rebuilder.py +astroid/scoped_nodes.py +astroid/test_utils.py +astroid/utils.py astroid.egg-info/PKG-INFO astroid.egg-info/SOURCES.txt astroid.egg-info/dependency_links.txt astroid.egg-info/requires.txt astroid.egg-info/top_level.txt -brain/py2gi.py -brain/py2mechanize.py -brain/py2qt4.py -brain/py2stdlib.py -test/fulltest.sh -test/data/MyPyPa-0.1.0-py2.5.egg -test/data/MyPyPa-0.1.0-py2.5.zip -test/data/__init__.py -test/data/absimport.py -test/data/all.py -test/data/email.py -test/data/format.py -test/data/module.py -test/data/module2.py -test/data/noendingnewline.py -test/data/nonregr.py -test/data/notall.py -test/data/SSL1/Connection1.py -test/data/SSL1/__init__.py -test/data/appl/__init__.py -test/data/appl/myConnection.py -test/data2/__init__.py -test/data2/clientmodule_test.py -test/data2/suppliermodule_test.py -test/regrtest_data/descriptor_crash.py -test/regrtest_data/absimp/__init__.py -test/regrtest_data/absimp/string.py -test/regrtest_data/absimp/sidepackage/__init__.py -test/regrtest_data/package/__init__.py -test/regrtest_data/package/absimport.py -test/regrtest_data/package/hello.py -test/regrtest_data/package/import_package_subpackage_module.py -test/regrtest_data/package/subpackage/__init__.py -test/regrtest_data/package/subpackage/module.py \ No newline at end of file +astroid/brain/builtin_inference.py +astroid/brain/py2gi.py +astroid/brain/py2mechanize.py +astroid/brain/py2pytest.py +astroid/brain/py2qt4.py +astroid/brain/py2stdlib.py +astroid/brain/pynose.py +astroid/brain/pysix_moves.py +astroid/tests/__init__.py +astroid/tests/resources.py +astroid/tests/unittest_brain.py +astroid/tests/unittest_builder.py +astroid/tests/unittest_inference.py +astroid/tests/unittest_inspector.py +astroid/tests/unittest_lookup.py +astroid/tests/unittest_manager.py +astroid/tests/unittest_modutils.py +astroid/tests/unittest_nodes.py +astroid/tests/unittest_peephole.py +astroid/tests/unittest_protocols.py +astroid/tests/unittest_python3.py +astroid/tests/unittest_raw_building.py +astroid/tests/unittest_regrtest.py +astroid/tests/unittest_scoped_nodes.py +astroid/tests/unittest_utils.py +astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.egg +astroid/tests/testdata/python2/data/MyPyPa-0.1.0-py2.5.zip +astroid/tests/testdata/python2/data/__init__.py +astroid/tests/testdata/python2/data/absimport.py +astroid/tests/testdata/python2/data/all.py +astroid/tests/testdata/python2/data/clientmodule_test.py +astroid/tests/testdata/python2/data/descriptor_crash.py +astroid/tests/testdata/python2/data/email.py +astroid/tests/testdata/python2/data/format.py +astroid/tests/testdata/python2/data/joined_strings.py +astroid/tests/testdata/python2/data/module.py +astroid/tests/testdata/python2/data/module2.py +astroid/tests/testdata/python2/data/noendingnewline.py +astroid/tests/testdata/python2/data/nonregr.py +astroid/tests/testdata/python2/data/notall.py +astroid/tests/testdata/python2/data/recursion.py +astroid/tests/testdata/python2/data/suppliermodule_test.py +astroid/tests/testdata/python2/data/SSL1/Connection1.py +astroid/tests/testdata/python2/data/SSL1/__init__.py +astroid/tests/testdata/python2/data/absimp/__init__.py +astroid/tests/testdata/python2/data/absimp/string.py +astroid/tests/testdata/python2/data/absimp/sidepackage/__init__.py +astroid/tests/testdata/python2/data/appl/__init__.py +astroid/tests/testdata/python2/data/appl/myConnection.py +astroid/tests/testdata/python2/data/find_test/__init__.py +astroid/tests/testdata/python2/data/find_test/module.py +astroid/tests/testdata/python2/data/find_test/module2.py +astroid/tests/testdata/python2/data/find_test/noendingnewline.py +astroid/tests/testdata/python2/data/find_test/nonregr.py +astroid/tests/testdata/python2/data/lmfp/__init__.py +astroid/tests/testdata/python2/data/lmfp/foo.py +astroid/tests/testdata/python2/data/module1abs/__init__.py +astroid/tests/testdata/python2/data/module1abs/core.py +astroid/tests/testdata/python2/data/package/__init__.py +astroid/tests/testdata/python2/data/package/absimport.py +astroid/tests/testdata/python2/data/package/hello.py +astroid/tests/testdata/python2/data/package/import_package_subpackage_module.py +astroid/tests/testdata/python2/data/package/subpackage/__init__.py +astroid/tests/testdata/python2/data/package/subpackage/module.py +astroid/tests/testdata/python2/data/unicode_package/__init__.py +astroid/tests/testdata/python2/data/unicode_package/core/__init__.py +astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.egg +astroid/tests/testdata/python3/data/MyPyPa-0.1.0-py2.5.zip +astroid/tests/testdata/python3/data/__init__.py +astroid/tests/testdata/python3/data/absimport.py +astroid/tests/testdata/python3/data/all.py +astroid/tests/testdata/python3/data/clientmodule_test.py +astroid/tests/testdata/python3/data/descriptor_crash.py +astroid/tests/testdata/python3/data/email.py +astroid/tests/testdata/python3/data/format.py +astroid/tests/testdata/python3/data/joined_strings.py +astroid/tests/testdata/python3/data/module.py +astroid/tests/testdata/python3/data/module2.py +astroid/tests/testdata/python3/data/noendingnewline.py +astroid/tests/testdata/python3/data/nonregr.py +astroid/tests/testdata/python3/data/notall.py +astroid/tests/testdata/python3/data/recursion.py +astroid/tests/testdata/python3/data/suppliermodule_test.py +astroid/tests/testdata/python3/data/SSL1/Connection1.py +astroid/tests/testdata/python3/data/SSL1/__init__.py +astroid/tests/testdata/python3/data/absimp/__init__.py +astroid/tests/testdata/python3/data/absimp/string.py +astroid/tests/testdata/python3/data/absimp/sidepackage/__init__.py +astroid/tests/testdata/python3/data/appl/__init__.py +astroid/tests/testdata/python3/data/appl/myConnection.py +astroid/tests/testdata/python3/data/find_test/__init__.py +astroid/tests/testdata/python3/data/find_test/module.py +astroid/tests/testdata/python3/data/find_test/module2.py +astroid/tests/testdata/python3/data/find_test/noendingnewline.py +astroid/tests/testdata/python3/data/find_test/nonregr.py +astroid/tests/testdata/python3/data/lmfp/__init__.py +astroid/tests/testdata/python3/data/lmfp/foo.py +astroid/tests/testdata/python3/data/module1abs/__init__.py +astroid/tests/testdata/python3/data/module1abs/core.py +astroid/tests/testdata/python3/data/package/__init__.py +astroid/tests/testdata/python3/data/package/absimport.py +astroid/tests/testdata/python3/data/package/hello.py +astroid/tests/testdata/python3/data/package/import_package_subpackage_module.py +astroid/tests/testdata/python3/data/package/subpackage/__init__.py +astroid/tests/testdata/python3/data/package/subpackage/module.py +astroid/tests/testdata/python3/data/unicode_package/__init__.py +astroid/tests/testdata/python3/data/unicode_package/core/__init__.py \ No newline at end of file diff -Nru astroid-1.0.1/bases.py astroid-1.3.8/bases.py --- astroid-1.0.1/bases.py 2013-07-29 15:04:24.000000000 +0000 +++ astroid-1.3.8/bases.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,612 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""This module contains base classes and functions for the nodes and some -inference utils. -""" - -__docformat__ = "restructuredtext en" - -import sys -from contextlib import contextmanager - -from astroid.exceptions import (InferenceError, AstroidError, NotFoundError, - UnresolvableName, UseInferenceDefault) - - -if sys.version_info >= (3, 0): - BUILTINS = 'builtins' -else: - BUILTINS = '__builtin__' - - -class Proxy(object): - """a simple proxy object""" - - _proxied = None # proxied object may be set by class or by instance - - def __init__(self, proxied=None): - if proxied is not None: - self._proxied = proxied - - def __getattr__(self, name): - if name == '_proxied': - return getattr(self.__class__, '_proxied') - if name in self.__dict__: - return self.__dict__[name] - return getattr(self._proxied, name) - - def infer(self, context=None): - yield self - - -# Inference ################################################################## - -class InferenceContext(object): - __slots__ = ('path', 'lookupname', 'callcontext', 'boundnode') - - def __init__(self, path=None): - if path is None: - self.path = set() - else: - self.path = path - self.lookupname = None - self.callcontext = None - self.boundnode = None - - def push(self, node): - name = self.lookupname - if (node, name) in self.path: - raise StopIteration() - self.path.add( (node, name) ) - - def clone(self): - # XXX copy lookupname/callcontext ? - clone = InferenceContext(self.path) - clone.callcontext = self.callcontext - clone.boundnode = self.boundnode - return clone - - @contextmanager - def restore_path(self): - path = set(self.path) - yield - self.path = path - -def copy_context(context): - if context is not None: - return context.clone() - else: - return InferenceContext() - - -def _infer_stmts(stmts, context, frame=None): - """return an iterator on statements inferred by each statement in - """ - stmt = None - infered = False - if context is not None: - name = context.lookupname - context = context.clone() - else: - name = None - context = InferenceContext() - for stmt in stmts: - if stmt is YES: - yield stmt - infered = True - continue - context.lookupname = stmt._infer_name(frame, name) - try: - for infered in stmt.infer(context): - yield infered - infered = True - except UnresolvableName: - continue - except InferenceError: - yield YES - infered = True - if not infered: - raise InferenceError(str(stmt)) - - -# special inference objects (e.g. may be returned as nodes by .infer()) ####### - -class _Yes(object): - """a yes object""" - def __repr__(self): - return 'YES' - def __getattribute__(self, name): - if name == 'next': - raise AttributeError('next method should not be called') - if name.startswith('__') and name.endswith('__'): - # to avoid inspection pb - return super(_Yes, self).__getattribute__(name) - return self - def __call__(self, *args, **kwargs): - return self - - -YES = _Yes() - - -class Instance(Proxy): - """a special node representing a class instance""" - def getattr(self, name, context=None, lookupclass=True): - try: - values = self._proxied.instance_attr(name, context) - except NotFoundError: - if name == '__class__': - return [self._proxied] - if lookupclass: - # class attributes not available through the instance - # unless they are explicitly defined - if name in ('__name__', '__bases__', '__mro__', '__subclasses__'): - return self._proxied.local_attr(name) - return self._proxied.getattr(name, context) - raise NotFoundError(name) - # since we've no context information, return matching class members as - # well - if lookupclass: - try: - return values + self._proxied.getattr(name, context) - except NotFoundError: - pass - return values - - def igetattr(self, name, context=None): - """inferred getattr""" - try: - # XXX frame should be self._proxied, or not ? - get_attr = self.getattr(name, context, lookupclass=False) - return _infer_stmts(self._wrap_attr(get_attr, context), context, - frame=self) - except NotFoundError: - try: - # fallback to class'igetattr since it has some logic to handle - # descriptors - return self._wrap_attr(self._proxied.igetattr(name, context), - context) - except NotFoundError: - raise InferenceError(name) - - def _wrap_attr(self, attrs, context=None): - """wrap bound methods of attrs in a InstanceMethod proxies""" - for attr in attrs: - if isinstance(attr, UnboundMethod): - if BUILTINS + '.property' in attr.decoratornames(): - for infered in attr.infer_call_result(self, context): - yield infered - else: - yield BoundMethod(attr, self) - else: - yield attr - - def infer_call_result(self, caller, context=None): - """infer what a class instance is returning when called""" - infered = False - for node in self._proxied.igetattr('__call__', context): - for res in node.infer_call_result(caller, context): - infered = True - yield res - if not infered: - raise InferenceError() - - def __repr__(self): - return '' % (self._proxied.root().name, - self._proxied.name, - id(self)) - def __str__(self): - return 'Instance of %s.%s' % (self._proxied.root().name, - self._proxied.name) - - def callable(self): - try: - self._proxied.getattr('__call__') - return True - except NotFoundError: - return False - - def pytype(self): - return self._proxied.qname() - - def display_type(self): - return 'Instance of' - - -class UnboundMethod(Proxy): - """a special node representing a method not bound to an instance""" - def __repr__(self): - frame = self._proxied.parent.frame() - return '<%s %s of %s at 0x%s' % (self.__class__.__name__, - self._proxied.name, - frame.qname(), id(self)) - - def is_bound(self): - return False - - def getattr(self, name, context=None): - if name == 'im_func': - return [self._proxied] - return super(UnboundMethod, self).getattr(name, context) - - def igetattr(self, name, context=None): - if name == 'im_func': - return iter((self._proxied,)) - return super(UnboundMethod, self).igetattr(name, context) - - def infer_call_result(self, caller, context): - # If we're unbound method __new__ of builtin object, the result is an - # instance of the class given as first argument. - if (self._proxied.name == '__new__' and - self._proxied.parent.frame().qname() == '%s.object' % BUILTINS): - return (x is YES and x or Instance(x) for x in caller.args[0].infer()) - return self._proxied.infer_call_result(caller, context) - - -class BoundMethod(UnboundMethod): - """a special node representing a method bound to an instance""" - def __init__(self, proxy, bound): - UnboundMethod.__init__(self, proxy) - self.bound = bound - - def is_bound(self): - return True - - def infer_call_result(self, caller, context): - context = context.clone() - context.boundnode = self.bound - return self._proxied.infer_call_result(caller, context) - - -class Generator(Instance): - """a special node representing a generator. - - Proxied class is set once for all in raw_building. - """ - def callable(self): - return False - - def pytype(self): - return '%s.generator' % BUILTINS - - def display_type(self): - return 'Generator' - - def __repr__(self): - return '' % (self._proxied.name, self.lineno, id(self)) - - def __str__(self): - return 'Generator(%s)' % (self._proxied.name) - - -# decorators ################################################################## - -def path_wrapper(func): - """return the given infer function wrapped to handle the path""" - def wrapped(node, context=None, _func=func, **kwargs): - """wrapper function handling context""" - if context is None: - context = InferenceContext() - context.push(node) - yielded = set() - for res in _func(node, context, **kwargs): - # unproxy only true instance, not const, tuple, dict... - if res.__class__ is Instance: - ares = res._proxied - else: - ares = res - if not ares in yielded: - yield res - yielded.add(ares) - return wrapped - -def yes_if_nothing_infered(func): - def wrapper(*args, **kwargs): - infered = False - for node in func(*args, **kwargs): - infered = True - yield node - if not infered: - yield YES - return wrapper - -def raise_if_nothing_infered(func): - def wrapper(*args, **kwargs): - infered = False - for node in func(*args, **kwargs): - infered = True - yield node - if not infered: - raise InferenceError() - return wrapper - - -# Node ###################################################################### - -class NodeNG(object): - """Base Class for all Astroid node classes. - - It represents a node of the new abstract syntax tree. - """ - is_statement = False - optional_assign = False # True for For (and for Comprehension if py <3.0) - is_function = False # True for Function nodes - # attributes below are set by the builder module or by raw factories - lineno = None - fromlineno = None - tolineno = None - col_offset = None - # parent node in the tree - parent = None - # attributes containing child node(s) redefined in most concrete classes: - _astroid_fields = () - # instance specific inference function infer(node, context) - _explicit_inference = None - - def infer(self, context=None, **kwargs): - """main interface to the interface system, return a generator on infered - values. - - If the instance has some explicit inference function set, it will be - called instead of the default interface. - """ - if self._explicit_inference is not None: - # explicit_inference is not bound, give it self explicitly - try: - return self._explicit_inference(self, context, **kwargs) - except UseInferenceDefault: - pass - return self._infer(context, **kwargs) - - def _repr_name(self): - """return self.name or self.attrname or '' for nice representation""" - return getattr(self, 'name', getattr(self, 'attrname', '')) - - def __str__(self): - return '%s(%s)' % (self.__class__.__name__, self._repr_name()) - - def __repr__(self): - return '<%s(%s) l.%s [%s] at Ox%x>' % (self.__class__.__name__, - self._repr_name(), - self.fromlineno, - self.root().name, - id(self)) - - - def accept(self, visitor): - klass = self.__class__.__name__ - func = getattr(visitor, "visit_" + self.__class__.__name__.lower()) - return func(self) - - def get_children(self): - for field in self._astroid_fields: - attr = getattr(self, field) - if attr is None: - continue - if isinstance(attr, (list, tuple)): - for elt in attr: - yield elt - else: - yield attr - - def last_child(self): - """an optimized version of list(get_children())[-1]""" - for field in self._astroid_fields[::-1]: - attr = getattr(self, field) - if not attr: # None or empty listy / tuple - continue - if isinstance(attr, (list, tuple)): - return attr[-1] - else: - return attr - return None - - def parent_of(self, node): - """return true if i'm a parent of the given node""" - parent = node.parent - while parent is not None: - if self is parent: - return True - parent = parent.parent - return False - - def statement(self): - """return the first parent node marked as statement node""" - if self.is_statement: - return self - return self.parent.statement() - - def frame(self): - """return the first parent frame node (i.e. Module, Function or Class) - """ - return self.parent.frame() - - def scope(self): - """return the first node defining a new scope (i.e. Module, Function, - Class, Lambda but also GenExpr) - """ - return self.parent.scope() - - def root(self): - """return the root node of the tree, (i.e. a Module)""" - if self.parent: - return self.parent.root() - return self - - def child_sequence(self, child): - """search for the right sequence where the child lies in""" - for field in self._astroid_fields: - node_or_sequence = getattr(self, field) - if node_or_sequence is child: - return [node_or_sequence] - # /!\ compiler.ast Nodes have an __iter__ walking over child nodes - if isinstance(node_or_sequence, (tuple, list)) and child in node_or_sequence: - return node_or_sequence - else: - msg = 'Could not find %s in %s\'s children' - raise AstroidError(msg % (repr(child), repr(self))) - - def locate_child(self, child): - """return a 2-uple (child attribute name, sequence or node)""" - for field in self._astroid_fields: - node_or_sequence = getattr(self, field) - # /!\ compiler.ast Nodes have an __iter__ walking over child nodes - if child is node_or_sequence: - return field, child - if isinstance(node_or_sequence, (tuple, list)) and child in node_or_sequence: - return field, node_or_sequence - msg = 'Could not find %s in %s\'s children' - raise AstroidError(msg % (repr(child), repr(self))) - # FIXME : should we merge child_sequence and locate_child ? locate_child - # is only used in are_exclusive, child_sequence one time in pylint. - - def next_sibling(self): - """return the next sibling statement""" - return self.parent.next_sibling() - - def previous_sibling(self): - """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] - - def set_line_info(self, lastchild): - if self.lineno is None: - self.fromlineno = self._fixed_source_line() - else: - self.fromlineno = self.lineno - if lastchild is None: - self.tolineno = self.fromlineno - else: - self.tolineno = lastchild.tolineno - return - # 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 = _node.get_children().next() - 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 - """ - return lineno, self.tolineno - - def set_local(self, name, stmt): - """delegate to a scoped parent handling a locals dictionary""" - self.parent.set_local(name, stmt) - - def nodes_of_class(self, klass, skip_klass=None): - """return an iterator on nodes which are instance of the given class(es) - - klass may be a class object or a tuple of class objects - """ - if isinstance(self, klass): - yield self - for child_node in self.get_children(): - if skip_klass is not None and isinstance(child_node, skip_klass): - continue - for matching in child_node.nodes_of_class(klass, skip_klass): - yield matching - - def _infer_name(self, frame, name): - # overridden for From, Import, Global, TryExcept and Arguments - return None - - def _infer(self, context=None): - """we don't know how to resolve a statement by default""" - # this method is overridden by most concrete classes - raise InferenceError(self.__class__.__name__) - - def infered(self): - '''return list of infered values for a more simple inference usage''' - return list(self.infer()) - - def instanciate_class(self): - """instanciate a node if it is a Class node, else return self""" - return self - - def has_base(self, node): - return False - - def callable(self): - return False - - def eq(self, value): - return False - - def as_string(self): - from astroid.as_string import to_code - return to_code(self) - - def repr_tree(self, ids=False): - from astroid.as_string import dump - return dump(self) - - -class Statement(NodeNG): - """Statement node adding a few attributes""" - is_statement = True - - def next_sibling(self): - """return the next sibling statement""" - stmts = self.parent.child_sequence(self) - index = stmts.index(self) - try: - return stmts[index +1] - except IndexError: - pass - - def previous_sibling(self): - """return the previous sibling statement""" - stmts = self.parent.child_sequence(self) - index = stmts.index(self) - if index >= 1: - return stmts[index -1] diff -Nru astroid-1.0.1/brain/py2gi.py astroid-1.3.8/brain/py2gi.py --- astroid-1.0.1/brain/py2gi.py 2013-10-18 15:34:05.000000000 +0000 +++ astroid-1.3.8/brain/py2gi.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -"""Astroid hooks for the Python 2 GObject introspection bindings. - -Helps with understanding everything imported from 'gi.repository' -""" - -import inspect -import sys - -from astroid import MANAGER, AstroidBuildingException -from astroid.builder import AstroidBuilder - - -_inspected_modules = {} - - -def _gi_build_stub(parent): - """ - Inspect the passed module recursively and build stubs for functions, - classes, etc. - """ - classes = {} - functions = {} - constants = {} - methods = {} - for name in dir(parent): - if not name or name.startswith("__"): - # GLib.IConv has a parameter named "" :/ - continue - try: - obj = getattr(parent, name) - except: - continue - - if inspect.isclass(obj): - classes[name] = obj - elif (inspect.isfunction(obj) or - inspect.isbuiltin(obj)): - functions[name] = obj - elif (inspect.ismethod(obj) or - inspect.ismethoddescriptor(obj)): - methods[name] = obj - elif type(obj) in [int, str]: - constants[name] = obj - elif (str(obj).startswith(". -"""The AstroidBuilder makes astroid from living object and / or from _ast - -The builder is not thread safe and can't be used to parse different sources -at the same time. -""" - -__docformat__ = "restructuredtext en" - -import sys -from os.path import splitext, basename, exists, abspath - -from logilab.common.modutils import modpath_from_file - -from astroid.exceptions import AstroidBuildingException, InferenceError -from astroid.raw_building import InspectBuilder -from astroid.rebuilder import TreeRebuilder -from astroid.manager import AstroidManager -from astroid.bases import YES, Instance - -from _ast import PyCF_ONLY_AST -def parse(string): - return compile(string, "", 'exec', PyCF_ONLY_AST) - -if sys.version_info >= (3, 0): - from tokenize import detect_encoding - - def open_source_file(filename): - byte_stream = open(filename, 'bU') - encoding = detect_encoding(byte_stream.readline)[0] - stream = open(filename, 'U', encoding=encoding) - try: - data = stream.read() - except UnicodeError, uex: # wrong encodingg - # detect_encoding returns utf-8 if no encoding specified - msg = 'Wrong (%s) or no encoding specified' % encoding - raise AstroidBuildingException(msg) - return stream, encoding, data - -else: - import re - - _ENCODING_RGX = re.compile("\s*#+.*coding[:=]\s*([-\w.]+)") - - def _guess_encoding(string): - """get encoding from a python file as string or return None if not found - """ - # check for UTF-8 byte-order mark - if string.startswith('\xef\xbb\xbf'): - return 'UTF-8' - for line in string.split('\n', 2)[:2]: - # check for encoding declaration - match = _ENCODING_RGX.match(line) - if match is not None: - return match.group(1) - - def open_source_file(filename): - """get data for parsing a file""" - stream = open(filename, 'U') - data = stream.read() - encoding = _guess_encoding(data) - return stream, encoding, data - -# ast NG builder ############################################################## - -MANAGER = AstroidManager() - -class AstroidBuilder(InspectBuilder): - """provide astroid building methods""" - - def __init__(self, manager=None): - InspectBuilder.__init__(self) - self._manager = manager or MANAGER - - def module_build(self, module, modname=None): - """build an astroid from a living module instance - """ - node = None - path = getattr(module, '__file__', None) - if path is not None: - path_, ext = splitext(module.__file__) - if ext in ('.py', '.pyc', '.pyo') and exists(path_ + '.py'): - node = self.file_build(path_ + '.py', modname) - if node is None: - # this is a built-in module - # get a partial representation by introspection - node = self.inspect_build(module, modname=modname, path=path) - return node - - def file_build(self, path, modname=None): - """build astroid from a source code file (i.e. from an ast) - - path is expected to be a python source file - """ - try: - stream, encoding, data = open_source_file(path) - except IOError, exc: - msg = 'Unable to load file %r (%s)' % (path, exc) - raise AstroidBuildingException(msg) - except SyntaxError, exc: # py3k encoding specification error - raise AstroidBuildingException(exc) - except LookupError, exc: # unknown encoding - raise AstroidBuildingException(exc) - # get module name if necessary - if modname is None: - try: - modname = '.'.join(modpath_from_file(path)) - except ImportError: - modname = splitext(basename(path))[0] - # build astroid representation - node = self.string_build(data, modname, path) - node.file_encoding = encoding - return node - - def string_build(self, data, modname='', path=None): - """build astroid from source code string and return rebuilded astroid""" - module = self._data_build(data, modname, path) - self._manager.astroid_cache[module.name] = module - # post tree building steps after we stored the module in the cache: - for from_node in module._from_nodes: - self.add_from_names_to_locals(from_node) - # handle delayed assattr nodes - for delayed in module._delayed_assattr: - self.delayed_assattr(delayed) - return module - - def _data_build(self, data, modname, path): - """build tree node from data and add some informations""" - # this method could be wrapped with a pickle/cache function - node = parse(data + '\n') - if path is not None: - node_file = abspath(path) - else: - node_file = '' - if modname.endswith('.__init__'): - modname = modname[:-9] - package = True - else: - package = path and path.find('__init__.py') > -1 or False - rebuilder = TreeRebuilder(self._manager) - module = rebuilder.visit_module(node, modname, package) - module.file = module.path = node_file - module._from_nodes = rebuilder._from_nodes - module._delayed_assattr = rebuilder._delayed_assattr - return module - - def add_from_names_to_locals(self, node): - """store imported names to the locals; - resort the locals if coming from a delayed node - """ - - _key_func = lambda node: node.fromlineno - def sort_locals(my_list): - my_list.sort(key=_key_func) - for (name, asname) in node.names: - if name == '*': - try: - imported = node.root().import_module(node.modname) - except AstroidBuildingException: - continue - for name in imported.wildcard_import_names(): - node.parent.set_local(name, node) - sort_locals(node.parent.scope().locals[name]) - else: - node.parent.set_local(asname or name, node) - sort_locals(node.parent.scope().locals[asname or name]) - - def delayed_assattr(self, node): - """visit a AssAttr node -> add name to locals, handle members - definition - """ - try: - frame = node.frame() - for infered in node.expr.infer(): - if infered is YES: - continue - try: - if infered.__class__ is Instance: - infered = infered._proxied - iattrs = infered.instance_attrs - elif isinstance(infered, Instance): - # Const, Tuple, ... we may be wrong, may be not, but - # anyway we don't want to pollute builtin's namespace - continue - elif infered.is_function: - iattrs = infered.instance_attrs - else: - iattrs = infered.locals - except AttributeError: - # XXX log error - #import traceback - #traceback.print_exc() - continue - values = iattrs.setdefault(node.attrname, []) - if node in values: - continue - # get assign in __init__ first XXX useful ? - if frame.name == '__init__' and values and not \ - values[0].frame().name == '__init__': - values.insert(0, node) - else: - values.append(node) - except InferenceError: - pass - diff -Nru astroid-1.0.1/ChangeLog astroid-1.3.8/ChangeLog --- astroid-1.0.1/ChangeLog 2013-10-18 15:34:05.000000000 +0000 +++ astroid-1.3.8/ChangeLog 2015-08-02 19:37:44.000000000 +0000 @@ -1,6 +1,251 @@ Change log for the astroid package (used to be astng) ===================================================== +2015-08-02 -- 1.3.8 + + * Backport of 40e3176, which fixes issue #84. + +2015-07-27 -- 1.3.7 + + * Improve the inference of six.moves, especially when using `from ... import ...` + syntax. Also, we added a new fail import hook for six.moves, which fixes the + import-error false positive from pylint. Closes issue #107. + +2015-03-14 -- 1.3.6 + + * Class.slots raises NotImplementedError for old style classes. + Closes issue #67. + + * Add a new option to AstroidManager, `optimize_ast`, which + controls if peephole optimizer should be enabled or not. + This prevents a regression, where the visit_binop method + wasn't called anymore with astroid 1.3.5, due to the differences + in the resulting AST. Closes issue #82. + + +2015-03-11 -- 1.3.5 + + * Add the ability to optimize small ast subtrees, + with the first use in the optimization of multiple + BinOp nodes. This removes recursivity in the rebuilder + when dealing with a lot of small strings joined by the + addition operator. Closes issue #59. + + * Obtain the methods for the nose brain tip through an + unittest.TestCase instance. Closes Pylint issue #457. + + * Fix a crash which occurred when a class was the ancestor + of itself. Closes issue #78. + + * Improve the scope_lookup method for Classes regarding qualified + objects, with an attribute name exactly as one provided in the + class itself. + + For example, a class containing an attribute 'first', + which was also an import and which had, as a base, a qualified name + or a Gettattr node, in the form 'module.first', then Pylint would + have inferred the `first` name as the function from the Class, + not the import. Closes Pylint issue #466. + + * Implement the assigned_stmts operation for Starred nodes, + which was omitted when support for Python 3 was added in astroid. + Closes issue #36. + + +2015-01-17 -- 1.3.4 + + * Get the first element from the method list when obtaining + the functions from nose.tools.trivial. Closes Pylint issue #448. + +2015-01-16 -- 1.3.3 + + * Restore file_stream to a property, but deprecate it in favour of + the newly added method Module.stream. By using a method instead of a + property, it will be easier to properly close the file right + after it is used, which will ensure that no file descriptors are + leaked. Until now, due to the fact that a module was cached, + it was not possible to close the file_stream anywhere. + file_stream will start emitting PendingDeprecationWarnings in + astroid 1.4, DeprecationWarnings in astroid 1.5 and it will + be finally removed in astroid 1.6. + + * Add inference tips for 'tuple', 'list', 'dict' and 'set' builtins. + + * Add brain definition for most string and unicode methods + + * Changed the API for Class.slots. It returns None when the class + doesn't define any slots. Previously, for both the cases where + the class didn't have slots defined and when it had an empty list + of slots, Class.slots returned an empty list. + + * Add a new method to Class nodes, 'mro', for obtaining the + the method resolution order of the class. + + * Add brain tips for six.moves. Closes issue #63. + + * Improve the detection for functions decorated with decorators + which returns static or class methods. + + * .slots() can contain unicode strings on Python 2. + + * Add inference tips for nose.tools. + + +2014-11-22 -- 1.3.2 + + * Fixed a crash with invalid subscript index. + + * Implement proper base class semantics for Python 3, where + every class derives from object. + + * Allow more fine-grained control over C extension loading + in the manager. + +2014-11-21 -- 1.3.1 + + * Fixed a crash issue with the pytest brain module. + +2014-11-20 -- 1.3.0 + + * Fix a maximum recursion error occured during the inference, + where statements with the same name weren't filtered properly. + Closes pylint issue #295. + + * Check that EmptyNode has an underlying object in + EmptyNode.has_underlying_object. + + * Simplify the understanding of enum members. + + * Fix an infinite loop with decorator call chain inference, + where the decorator returns itself. Closes issue #50. + + * Various speed improvements. Patch by Alex Munroe. + + * Add pytest brain plugin. Patch by Robbie Coomber. + + * Support for Python versions < 2.7 has been dropped, and the + source has been made compatible with Python 2 and 3. Running + 2to3 on installation for Python 3 is not needed anymore. + + * astroid now depends on six. + + * modutils._module_file opens __init__.py in binary mode. + Closes issues #51 and #13. + + * Only C extensions from trusted sources (the standard library) + are loaded into the examining Python process to build an AST + from the live module. + + * Path names on case-insensitive filesystems are now properly + handled. This fixes the stdlib detection code on Windows. + + * Metaclass-generating functions like six.with_metaclass + are now supported via some explicit detection code. + + * astroid.register_module_extender has been added to generalize + the support for module extenders as used by many brain plugins. + + * brain plugins can now register hooks to handle failed imports, + as done by the gobject-introspection plugin. + + * The modules have been moved to a separate package directory, + `setup.py develop` now works correctly. + + +2014-08-24 -- 1.2.1 + + * Fix a crash occurred when inferring decorator call chain. + Closes issue #42. + + * Set the parent of vararg and kwarg nodes when inferring them. + Closes issue #43. + + * namedtuple inference knows about '_fields' attribute. + + * enum members knows about the methods from the enum class. + + * Name inference will lookup in the parent function + of the current scope, in case searching in the current scope + fails. + + * Inference of the functional form of the enums takes into + consideration the various inputs that enums accepts. + + * The inference engine handles binary operations (add, mul etc.) + between instances. + + * Fix an infinite loop in the inference, by returning a copy + of instance attributes, when calling 'instance_attr'. + Closes issue #34 (patch by Emile Anclin). + + * Don't crash when trying to infer unbound object.__new__ call. + Closes issue #11. + +2014-07-25 -- 1.2.0 + + * Function nodes can detect decorator call chain and see if they are + decorated with builtin descriptors (`classmethod` and `staticmethod`). + + * infer_call_result called on a subtype of the builtin type will now + return a new `Class` rather than an `Instance`. + + * `Class.metaclass()` now handles module-level __metaclass__ declaration + on python 2, and no longer looks at the __metaclass__ class attribute on + python 3. + + * Function nodes can detect if they are decorated with subclasses + of builtin descriptors when determining their type + (`classmethod` and `staticmethod`). + + * Add `slots` method to `Class` nodes, for retrieving + the list of valid slots it defines. + + * Expose function annotation to astroid: `Arguments` node + exposes 'varargannotation', 'kwargannotation' and 'annotations' + attributes, while `Function` node has the 'returns' attribute. + + * Backported most of the logilab.common.modutils module there, as + most things there are for pylint/astroid only and we want to be + able to fix them without requiring a new logilab.common release + + * Fix names grabed using wildcard import in "absolute import mode" + (ie with absolute_import activated from the __future__ or with + python 3). Fix pylint issue #58. + + * Add support in pylint-brain for understanding enum classes. + +2014-04-30 -- 1.1.1 + * `Class.metaclass()` looks in ancestors when the current class + does not define explicitly a metaclass. + + * Do not cache modules if a module with the same qname is already + known, and only return cached modules if both name and filepath + match. Fixes pylint Bitbucket issue #136. + +2014-04-18 -- 1.1.0 + * All class nodes are marked as new style classes for Py3k. + + * Add a `metaclass` function to `Class` nodes to + retrieve their metaclass. + + * Add a new YieldFrom node. + + * Add support for inferring arguments to namedtuple invocations. + + * Make sure that objects returned for namedtuple + inference have parents. + + * Don't crash when inferring nodes from `with` clauses + with multiple context managers. Closes #18. + + * Don't crash when a class has some __call__ method that is not + inferable. Closes #17. + + * Unwrap instances found in `.ancestors()`, by using their _proxied + class. + + + 2013-10-18 -- 1.0.1 * fix py3k/windows installation issue (issue #4) @@ -21,7 +266,7 @@ as abstract. * Allow transformation functions on any node, providing a - `register_transform` function on the manager instead of the + `register_transform` function on the manager instead of the `register_transformer` to make it more flexible wrt node selection * Use the new transformation API to provide support for namedtuple diff -Nru astroid-1.0.1/debian/changelog astroid-1.3.8/debian/changelog --- astroid-1.0.1/debian/changelog 2014-01-04 11:14:18.000000000 +0000 +++ astroid-1.3.8/debian/changelog 2015-11-05 20:23:22.000000000 +0000 @@ -1,3 +1,109 @@ +astroid (1.3.8-1~trusty) trusty; urgency=medium + + * Backport to trusty. + + -- Robert Bruce Park Thu, 05 Nov 2015 14:22:55 -0600 + +astroid (1.3.8-1) unstable; urgency=medium + + * New upstream release + * debian/control + - tighen logilab-common deps to >= 0.63.0 + + -- Sandro Tosi Tue, 04 Aug 2015 07:57:06 +0100 + +astroid (1.3.6-2) unstable; urgency=medium + + * upload to unstable + + -- Sandro Tosi Sun, 02 Aug 2015 00:11:06 +0100 + +astroid (1.3.6-1) experimental; urgency=medium + + * New upstream release + * debian/watch + - uses PyPI redirector + * debian/control + - add python{,3}-nose to b-d, needed to run tests + + -- Sandro Tosi Thu, 26 Mar 2015 00:28:54 +0000 + +astroid (1.3.4-1) experimental; urgency=medium + + * New upstream release + * debian/copyright + - extend upstream and packaging copyright years + - update upstream email contact + - update path location for new upstream code organization + * debian/control + - add six to dependencies + - add setuptoold to b-d + * debian/patches/* + - drop patched, they are now part of a release + * debian/watch + - update to the proper PyPI location + * debian/rules + - test dir has changed name, update rm command + + -- Sandro Tosi Sun, 01 Feb 2015 21:31:37 +0000 + +astroid (1.2.1-3) unstable; urgency=medium + + * debian/patches/afea46c0380956213976db2ce0f1e8f3cf6a0abc.patch + - enable fine-grained control over extensions loading; this fix is needed + after #591676 fix; Addresses: #772018 + + -- Sandro Tosi Mon, 08 Dec 2014 21:43:04 +0000 + +astroid (1.2.1-2) unstable; urgency=medium + + * debian/patches/e24cacb15e2e152db155fdca9197a8d1bf9ce235.patch + - Never load C extensions that are not from the standard library and also + never load any compiled Python files; thanks to Jakub Wilk for the report; + Closes: #591676 + + -- Sandro Tosi Sun, 23 Nov 2014 13:36:44 +0000 + +astroid (1.2.1-1) unstable; urgency=medium + + * New upstream release + * debian/watch + - update to support multiple tarball formats + * debian/control + - bump Standards-Version to 3.9.6 (no changes needed) + - add dh-python to b-d, that package will contain dh_python* scripts + + -- Sandro Tosi Sun, 02 Nov 2014 14:47:27 +0000 + +astroid (1.2.0-1) unstable; urgency=medium + + * New upstream release + + -- Sandro Tosi Sat, 09 Aug 2014 14:47:03 +0100 + +astroid (1.1.1-1) unstable; urgency=medium + + * New upstream release; Closes: #735327 + * debian/control + - switch me to Maintainer (team to Uploaders) + * debian/copyright + - extend upstream copyright years + * debian/patches/* + - removed, merged upstream + + -- Sandro Tosi Sun, 11 May 2014 17:43:01 +0200 + +astroid (1.0.1-2) unstable; urgency=low + + * debian/copyright + - document test/data/SSL1/Connection1.py copyright, as pointed out by + Thorsten Alteholz + * debian/patches/bts744225-fix-gi-introspection-issues.patch + - fix GI introspection issues; thanks to Leo Iannacone for the report; + Closes: #744225 + + -- Sandro Tosi Sat, 19 Apr 2014 19:57:08 +0200 + astroid (1.0.1-1) unstable; urgency=low * Initial release (Closes: #734075) diff -Nru astroid-1.0.1/debian/control astroid-1.3.8/debian/control --- astroid-1.0.1/debian/control 2014-01-04 10:40:47.000000000 +0000 +++ astroid-1.3.8/debian/control 2015-08-04 06:55:22.000000000 +0000 @@ -1,17 +1,17 @@ Source: astroid Section: python Priority: optional -Maintainer: Debian Python Modules Team -Uploaders: Sandro Tosi -Build-Depends: debhelper (>= 9.0.0), python, python3 -Standards-Version: 3.9.5 +Maintainer: Sandro Tosi +Uploaders: Debian Python Modules Team +Build-Depends: debhelper (>= 9.0.0), python, python3, dh-python, python-setuptools, python3-setuptools, python-nose, python3-nose +Standards-Version: 3.9.6 Homepage: http://www.astroid.org/ Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/astroid/trunk/ Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/astroid/trunk/ Package: python-astroid Architecture: all -Depends: ${python:Depends}, ${misc:Depends}, python-logilab-common (>= 0.60.0) +Depends: ${python:Depends}, ${misc:Depends}, python-logilab-common (>= 0.63.0), python-six Description: rebuild a new abstract syntax tree from Python's AST The aim of this module is to provide a common base representation of Python source code for projects such as pychecker, pyreverse, @@ -39,7 +39,7 @@ Package: python3-astroid Architecture: all -Depends: ${python3:Depends}, ${misc:Depends}, python3-logilab-common (>= 0.60.0) +Depends: ${python3:Depends}, ${misc:Depends}, python3-logilab-common (>= 0.63.0), python3-six Description: rebuild a new abstract syntax tree from Python's AST (Python3) The aim of this module is to provide a common base representation of Python source code for projects such as pychecker, pyreverse, diff -Nru astroid-1.0.1/debian/copyright astroid-1.3.8/debian/copyright --- astroid-1.0.1/debian/copyright 2014-01-03 15:24:05.000000000 +0000 +++ astroid-1.3.8/debian/copyright 2015-01-31 01:39:21.000000000 +0000 @@ -3,7 +3,7 @@ Source: http://www.astroid.org/ Files: * -Copyright: 2003-2013 Logilab +Copyright: 2003-2015 Logilab License: LGPL-2.1+ astroid is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the @@ -22,7 +22,7 @@ License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". Files: debian/* -Copyright: 2014 Sandro Tosi +Copyright: 2014-2015 Sandro Tosi License: LGPL-2.1+ astroid is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the @@ -40,7 +40,7 @@ On Debian systems, the complete text of the GNU Lesser General Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". -Files: test/unittest_brain.py +Files: astroid/tests/unittest_brain.py Copyright: Copyright 2013 Google Inc. All Rights Reserved. License: LGPL-2.1+ astroid is free software: you can redistribute it and/or modify it @@ -59,3 +59,5 @@ On Debian systems, the complete text of the GNU Lesser General Public License version 2.1 can be found in "/usr/share/common-licenses/LGPL-2.1". +Files: astroid/tests/testdata/python{2,3}/data/SSL1/Connection1.py +Copyright: Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. diff -Nru astroid-1.0.1/debian/rules astroid-1.3.8/debian/rules --- astroid-1.0.1/debian/rules 2014-01-04 11:12:08.000000000 +0000 +++ astroid-1.3.8/debian/rules 2015-02-01 21:18:20.000000000 +0000 @@ -18,7 +18,7 @@ --root=$(CURDIR)/debian/$(PKG3)/ \ --install-layout=deb # remove tests files - rm -rf debian/*/usr/lib/python*/*-packages/astroid/test + rm -rf debian/*/usr/lib/python*/*-packages/astroid/tests override_dh_installdocs: dh_installdocs -i README diff -Nru astroid-1.0.1/debian/watch astroid-1.3.8/debian/watch --- astroid-1.0.1/debian/watch 2014-01-03 15:24:05.000000000 +0000 +++ astroid-1.3.8/debian/watch 2015-03-25 11:28:34.000000000 +0000 @@ -1,4 +1,3 @@ -# Compulsory line, this is a version 3 file version=3 - -https://pypi.python.org/packages/source/a/astroid/astroid-(.*)\.tar.gz +opts=uversionmangle=s/(rc|a|b|c)/~$1/ \ +http://pypi.debian.net/astroid/astroid-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) \ No newline at end of file diff -Nru astroid-1.0.1/exceptions.py astroid-1.3.8/exceptions.py --- astroid-1.0.1/exceptions.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/exceptions.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""this module contains exceptions used in the astroid library - -""" - -__doctype__ = "restructuredtext en" - -class AstroidError(Exception): - """base exception class for all astroid related exceptions""" - -class AstroidBuildingException(AstroidError): - """exception class when we are unable to build an astroid representation""" - -class ResolveError(AstroidError): - """base class of astroid resolution/inference error""" - -class NotFoundError(ResolveError): - """raised when we are unable to resolve a name""" - -class InferenceError(ResolveError): - """raised when we are unable to infer a node""" - -class UseInferenceDefault(Exception): - """exception to be raised in custom inference function to indicate that it - should go back to the default behaviour - """ - -class UnresolvableName(InferenceError): - """raised when we are unable to resolve a name""" - -class NoDefault(AstroidError): - """raised by function's `default_value` method when an argument has - no default value - """ - diff -Nru astroid-1.0.1/inference.py astroid-1.3.8/inference.py --- astroid-1.0.1/inference.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/inference.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,388 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""this module contains a set of functions to handle inference on astroid trees -""" - -__doctype__ = "restructuredtext en" - -from itertools import chain - -from astroid import nodes - -from astroid.manager import AstroidManager -from astroid.exceptions import (AstroidError, - InferenceError, NoDefault, NotFoundError, UnresolvableName) -from astroid.bases import YES, Instance, InferenceContext, \ - _infer_stmts, copy_context, path_wrapper, raise_if_nothing_infered -from astroid.protocols import _arguments_infer_argname - -MANAGER = AstroidManager() - - -class CallContext: - """when inferring a function call, this class is used to remember values - given as argument - """ - def __init__(self, args, starargs, dstarargs): - self.args = [] - self.nargs = {} - for arg in args: - if isinstance(arg, nodes.Keyword): - self.nargs[arg.arg] = arg.value - else: - self.args.append(arg) - self.starargs = starargs - self.dstarargs = dstarargs - - def infer_argument(self, funcnode, name, context): - """infer a function argument value according to the call context""" - # 1. search in named keywords - try: - return self.nargs[name].infer(context) - except KeyError: - # Function.args.args can be None in astroid (means that we don't have - # information on argnames) - argindex = funcnode.args.find_argname(name)[0] - if argindex is not None: - # 2. first argument of instance/class method - if argindex == 0 and funcnode.type in ('method', 'classmethod'): - if context.boundnode is not None: - boundnode = context.boundnode - else: - # XXX can do better ? - boundnode = funcnode.parent.frame() - if funcnode.type == 'method': - if not isinstance(boundnode, Instance): - boundnode = Instance(boundnode) - return iter((boundnode,)) - if funcnode.type == 'classmethod': - return iter((boundnode,)) - # 2. search arg index - try: - return self.args[argindex].infer(context) - except IndexError: - pass - # 3. search in *args (.starargs) - if self.starargs is not None: - its = [] - for infered in self.starargs.infer(context): - if infered is YES: - its.append((YES,)) - continue - try: - its.append(infered.getitem(argindex, context).infer(context)) - except (InferenceError, AttributeError): - its.append((YES,)) - except (IndexError, TypeError): - continue - if its: - return chain(*its) - # 4. XXX search in **kwargs (.dstarargs) - if self.dstarargs is not None: - its = [] - for infered in self.dstarargs.infer(context): - if infered is YES: - its.append((YES,)) - continue - try: - its.append(infered.getitem(name, context).infer(context)) - except (InferenceError, AttributeError): - its.append((YES,)) - except (IndexError, TypeError): - continue - if its: - return chain(*its) - # 5. */** argument, (Tuple or Dict) - if name == funcnode.args.vararg: - return iter((nodes.const_factory(()))) - if name == funcnode.args.kwarg: - return iter((nodes.const_factory({}))) - # 6. return default value if any - try: - return funcnode.args.default_value(name).infer(context) - except NoDefault: - raise InferenceError(name) - - -# .infer method ############################################################### - - -def infer_end(self, context=None): - """inference's end for node such as Module, Class, Function, Const... - """ - yield self -nodes.Module._infer = infer_end -nodes.Class._infer = infer_end -nodes.Function._infer = infer_end -nodes.Lambda._infer = infer_end -nodes.Const._infer = infer_end -nodes.List._infer = infer_end -nodes.Tuple._infer = infer_end -nodes.Dict._infer = infer_end -nodes.Set._infer = infer_end - -def infer_name(self, context=None): - """infer a Name: use name lookup rules""" - frame, stmts = self.lookup(self.name) - if not stmts: - raise UnresolvableName(self.name) - context = context.clone() - context.lookupname = self.name - return _infer_stmts(stmts, context, frame) -nodes.Name._infer = path_wrapper(infer_name) -nodes.AssName.infer_lhs = infer_name # won't work with a path wrapper - - -def infer_callfunc(self, context=None): - """infer a CallFunc node by trying to guess what the function returns""" - callcontext = context.clone() - callcontext.callcontext = CallContext(self.args, self.starargs, self.kwargs) - callcontext.boundnode = None - for callee in self.func.infer(context): - if callee is YES: - yield callee - continue - try: - if hasattr(callee, 'infer_call_result'): - for infered in callee.infer_call_result(self, callcontext): - yield infered - except InferenceError: - ## XXX log error ? - continue -nodes.CallFunc._infer = path_wrapper(raise_if_nothing_infered(infer_callfunc)) - - -def infer_import(self, context=None, asname=True): - """infer an Import node: return the imported module/object""" - name = context.lookupname - if name is None: - raise InferenceError() - if asname: - yield self.do_import_module(self.real_name(name)) - else: - yield self.do_import_module(name) -nodes.Import._infer = path_wrapper(infer_import) - -def infer_name_module(self, name): - context = InferenceContext() - context.lookupname = name - return self.infer(context, asname=False) -nodes.Import.infer_name_module = infer_name_module - - -def infer_from(self, context=None, asname=True): - """infer a From nodes: return the imported module/object""" - name = context.lookupname - if name is None: - raise InferenceError() - if asname: - name = self.real_name(name) - module = self.do_import_module(self.modname) - try: - context = copy_context(context) - context.lookupname = name - return _infer_stmts(module.getattr(name, ignore_locals=module is self.root()), context) - except NotFoundError: - raise InferenceError(name) -nodes.From._infer = path_wrapper(infer_from) - - -def infer_getattr(self, context=None): - """infer a Getattr node by using getattr on the associated object""" - #context = context.clone() - for owner in self.expr.infer(context): - if owner is YES: - yield owner - continue - try: - context.boundnode = owner - for obj in owner.igetattr(self.attrname, context): - yield obj - context.boundnode = None - except (NotFoundError, InferenceError): - context.boundnode = None - except AttributeError: - # XXX method / function - context.boundnode = None -nodes.Getattr._infer = path_wrapper(raise_if_nothing_infered(infer_getattr)) -nodes.AssAttr.infer_lhs = raise_if_nothing_infered(infer_getattr) # # won't work with a path wrapper - - -def infer_global(self, context=None): - if context.lookupname is None: - raise InferenceError() - try: - return _infer_stmts(self.root().getattr(context.lookupname), context) - except NotFoundError: - raise InferenceError() -nodes.Global._infer = path_wrapper(infer_global) - - -def infer_subscript(self, context=None): - """infer simple subscription such as [1,2,3][0] or (1,2,3)[-1]""" - value = self.value.infer(context).next() - if value is YES: - yield YES - return - - index = self.slice.infer(context).next() - if index is YES: - yield YES - return - - if isinstance(index, nodes.Const): - try: - assigned = value.getitem(index.value, context) - except AttributeError: - raise InferenceError() - except (IndexError, TypeError): - yield YES - return - for infered in assigned.infer(context): - yield infered - else: - raise InferenceError() -nodes.Subscript._infer = path_wrapper(infer_subscript) -nodes.Subscript.infer_lhs = raise_if_nothing_infered(infer_subscript) - - -UNARY_OP_METHOD = {'+': '__pos__', - '-': '__neg__', - '~': '__invert__', - 'not': None, # XXX not '__nonzero__' - } - -def infer_unaryop(self, context=None): - for operand in self.operand.infer(context): - try: - yield operand.infer_unary_op(self.op) - except TypeError: - continue - except AttributeError: - meth = UNARY_OP_METHOD[self.op] - if meth is None: - yield YES - else: - try: - # XXX just suppose if the type implement meth, returned type - # will be the same - operand.getattr(meth) - yield operand - except GeneratorExit: - raise - except: - yield YES -nodes.UnaryOp._infer = path_wrapper(infer_unaryop) - - -BIN_OP_METHOD = {'+': '__add__', - '-': '__sub__', - '/': '__div__', - '//': '__floordiv__', - '*': '__mul__', - '**': '__power__', - '%': '__mod__', - '&': '__and__', - '|': '__or__', - '^': '__xor__', - '<<': '__lshift__', - '>>': '__rshift__', - } - -def _infer_binop(operator, operand1, operand2, context, failures=None): - if operand1 is YES: - yield operand1 - return - try: - for valnode in operand1.infer_binary_op(operator, operand2, context): - yield valnode - except AttributeError: - try: - # XXX just suppose if the type implement meth, returned type - # will be the same - operand1.getattr(BIN_OP_METHOD[operator]) - yield operand1 - except: - if failures is None: - yield YES - else: - failures.append(operand1) - -def infer_binop(self, context=None): - failures = [] - for lhs in self.left.infer(context): - for val in _infer_binop(self.op, lhs, self.right, context, failures): - yield val - for lhs in failures: - for rhs in self.right.infer(context): - for val in _infer_binop(self.op, rhs, lhs, context): - yield val -nodes.BinOp._infer = path_wrapper(infer_binop) - - -def infer_arguments(self, context=None): - name = context.lookupname - if name is None: - raise InferenceError() - return _arguments_infer_argname(self, name, context) -nodes.Arguments._infer = infer_arguments - - -def infer_ass(self, context=None): - """infer a AssName/AssAttr: need to inspect the RHS part of the - assign node - """ - stmt = self.statement() - if isinstance(stmt, nodes.AugAssign): - return stmt.infer(context) - stmts = list(self.assigned_stmts(context=context)) - return _infer_stmts(stmts, context) -nodes.AssName._infer = path_wrapper(infer_ass) -nodes.AssAttr._infer = path_wrapper(infer_ass) - -def infer_augassign(self, context=None): - failures = [] - for lhs in self.target.infer_lhs(context): - for val in _infer_binop(self.op, lhs, self.value, context, failures): - yield val - for lhs in failures: - for rhs in self.value.infer(context): - for val in _infer_binop(self.op, rhs, lhs, context): - yield val -nodes.AugAssign._infer = path_wrapper(infer_augassign) - - -# no infer method on DelName and DelAttr (expected InferenceError) - - -def infer_empty_node(self, context=None): - if not self.has_underlying_object(): - yield YES - else: - try: - for infered in MANAGER.infer_ast_from_something(self.object, - context=context): - yield infered - except AstroidError: - yield YES -nodes.EmptyNode._infer = path_wrapper(infer_empty_node) - - -def infer_index(self, context=None): - return self.value.infer(context) -nodes.Index._infer = infer_index diff -Nru astroid-1.0.1/__init__.py astroid-1.3.8/__init__.py --- astroid-1.0.1/__init__.py 2013-07-29 15:04:24.000000000 +0000 +++ astroid-1.3.8/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""Python Abstract Syntax Tree New Generation - -The aim of this module is to provide a common base representation of -python source code for projects such as pychecker, pyreverse, -pylint... Well, actually the development of this library is essentially -governed by pylint's needs. - -It extends class defined in the python's _ast module with some -additional methods and attributes. Instance attributes are added by a -builder object, which can either generate extended ast (let's call -them astroid ;) by visiting an existent ast tree or by inspecting living -object. Methods are added by monkey patching ast classes. - -Main modules are: - -* nodes and scoped_nodes for more information about methods and - attributes added to different node classes - -* the manager contains a high level object to get astroid trees from - source files and living objects. It maintains a cache of previously - constructed tree for quick access - -* builder contains the class responsible to build astroid trees -""" -__doctype__ = "restructuredtext en" - -import sys -import re -from operator import attrgetter - -# WARNING: internal imports order matters ! - -# make all exception classes accessible from astroid package -from astroid.exceptions import * - -# make all node classes accessible from astroid package -from astroid.nodes import * - -# trigger extra monkey-patching -from astroid import inference - -# more stuff available -from astroid import raw_building -from astroid.bases import YES, Instance, BoundMethod, UnboundMethod -from astroid.node_classes import are_exclusive, unpack_infer -from astroid.scoped_nodes import builtin_lookup - -# make a manager instance (borg) as well as Project and Package classes -# accessible from astroid package -from astroid.manager import AstroidManager, Project -MANAGER = AstroidManager() -del AstroidManager - -# transform utilities (filters and decorator) - -class AsStringRegexpPredicate(object): - """Class to be used as predicate that may be given to `register_transform` - - First argument is a regular expression that will be searched against the `as_string` - representation of the node onto which it's applied. - - If specified, the second argument is an `attrgetter` expression that will be - applied on the node first to get the actual node on which `as_string` should - be called. - """ - def __init__(self, regexp, expression=None): - self.regexp = re.compile(regexp) - self.expression = expression - - def __call__(self, node): - if self.expression is not None: - node = attrgetter(self.expression)(node) - return self.regexp.search(node.as_string()) - -def inference_tip(infer_function): - """Given an instance specific inference function, return a function to be - given to MANAGER.register_transform to set this inference function. - - Typical usage - - .. sourcecode:: python - - MANAGER.register_transform(CallFunc, inference_tip(infer_named_tuple), - AsStringRegexpPredicate('namedtuple', 'func')) - """ - def transform(node, infer_function=infer_function): - node._explicit_inference = infer_function - return node - return transform - -# load brain plugins -from os import listdir -from os.path import join, dirname -BRAIN_MODULES_DIR = join(dirname(__file__), 'brain') -if BRAIN_MODULES_DIR not in sys.path: - # add it to the end of the list so user path take precedence - sys.path.append(BRAIN_MODULES_DIR) -# load modules in this directory -for module in listdir(BRAIN_MODULES_DIR): - if module.endswith('.py'): - __import__(module[:-3]) diff -Nru astroid-1.0.1/inspector.py astroid-1.3.8/inspector.py --- astroid-1.0.1/inspector.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/inspector.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,275 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""visitor doing some postprocessing on the astroid tree. -Try to resolve definitions (namespace) dictionary, relationship... - -This module has been imported from pyreverse -""" - -__docformat__ = "restructuredtext en" - -from os.path import dirname - -from logilab.common.modutils import get_module_part, is_relative, \ - is_standard_module - -import astroid -from astroid.exceptions import InferenceError -from astroid.utils import LocalsVisitor - -class IdGeneratorMixIn: - """ - Mixin adding the ability to generate integer uid - """ - def __init__(self, start_value=0): - self.id_count = start_value - - def init_counter(self, start_value=0): - """init the id counter - """ - self.id_count = start_value - - def generate_id(self): - """generate a new identifier - """ - self.id_count += 1 - return self.id_count - - -class Linker(IdGeneratorMixIn, LocalsVisitor): - """ - walk on the project tree and resolve relationships. - - According to options the following attributes may be added to visited nodes: - - * uid, - a unique identifier for the node (on astroid.Project, astroid.Module, - astroid.Class and astroid.locals_type). Only if the linker has been instantiated - with tag=True parameter (False by default). - - * Function - a mapping from locals names to their bounded value, which may be a - constant like a string or an integer, or an astroid node (on astroid.Module, - astroid.Class and astroid.Function). - - * instance_attrs_type - as locals_type but for klass member attributes (only on astroid.Class) - - * implements, - list of implemented interface _objects_ (only on astroid.Class nodes) - """ - - def __init__(self, project, inherited_interfaces=0, tag=False): - IdGeneratorMixIn.__init__(self) - LocalsVisitor.__init__(self) - # take inherited interface in consideration or not - self.inherited_interfaces = inherited_interfaces - # tag nodes or not - self.tag = tag - # visited project - self.project = project - - - def visit_project(self, node): - """visit an astroid.Project node - - * optionally tag the node with a unique id - """ - if self.tag: - node.uid = self.generate_id() - for module in node.modules: - self.visit(module) - - def visit_package(self, node): - """visit an astroid.Package node - - * optionally tag the node with a unique id - """ - if self.tag: - node.uid = self.generate_id() - for subelmt in node.values(): - self.visit(subelmt) - - def visit_module(self, node): - """visit an astroid.Module node - - * set the locals_type mapping - * set the depends mapping - * optionally tag the node with a unique id - """ - if hasattr(node, 'locals_type'): - return - node.locals_type = {} - node.depends = [] - if self.tag: - node.uid = self.generate_id() - - def visit_class(self, node): - """visit an astroid.Class node - - * set the locals_type and instance_attrs_type mappings - * set the implements list and build it - * optionally tag the node with a unique id - """ - if hasattr(node, 'locals_type'): - return - node.locals_type = {} - if self.tag: - node.uid = self.generate_id() - # resolve ancestors - for baseobj in node.ancestors(recurs=False): - specializations = getattr(baseobj, 'specializations', []) - specializations.append(node) - baseobj.specializations = specializations - # resolve instance attributes - node.instance_attrs_type = {} - for assattrs in node.instance_attrs.values(): - for assattr in assattrs: - self.handle_assattr_type(assattr, node) - # resolve implemented interface - try: - node.implements = list(node.interfaces(self.inherited_interfaces)) - except InferenceError: - node.implements = () - - def visit_function(self, node): - """visit an astroid.Function node - - * set the locals_type mapping - * optionally tag the node with a unique id - """ - if hasattr(node, 'locals_type'): - return - node.locals_type = {} - if self.tag: - node.uid = self.generate_id() - - link_project = visit_project - link_module = visit_module - link_class = visit_class - link_function = visit_function - - def visit_assname(self, node): - """visit an astroid.AssName node - - handle locals_type - """ - # avoid double parsing done by different Linkers.visit - # running over the same project: - if hasattr(node, '_handled'): - return - node._handled = True - if node.name in node.frame(): - frame = node.frame() - else: - # the name has been defined as 'global' in the frame and belongs - # there. Btw the frame is not yet visited as the name is in the - # root locals; the frame hence has no locals_type attribute - frame = node.root() - try: - values = node.infered() - try: - already_infered = frame.locals_type[node.name] - for valnode in values: - if not valnode in already_infered: - already_infered.append(valnode) - except KeyError: - frame.locals_type[node.name] = values - except astroid.InferenceError: - pass - - def handle_assattr_type(self, node, parent): - """handle an astroid.AssAttr node - - handle instance_attrs_type - """ - try: - values = list(node.infer()) - try: - already_infered = parent.instance_attrs_type[node.attrname] - for valnode in values: - if not valnode in already_infered: - already_infered.append(valnode) - except KeyError: - parent.instance_attrs_type[node.attrname] = values - except astroid.InferenceError: - pass - - def visit_import(self, node): - """visit an astroid.Import node - - resolve module dependencies - """ - context_file = node.root().file - for name in node.names: - relative = is_relative(name[0], context_file) - self._imported_module(node, name[0], relative) - - - def visit_from(self, node): - """visit an astroid.From node - - resolve module dependencies - """ - basename = node.modname - context_file = node.root().file - if context_file is not None: - relative = is_relative(basename, context_file) - else: - relative = False - for name in node.names: - if name[0] == '*': - continue - # analyze dependencies - fullname = '%s.%s' % (basename, name[0]) - if fullname.find('.') > -1: - try: - # XXX: don't use get_module_part, missing package precedence - fullname = get_module_part(fullname, context_file) - except ImportError: - continue - if fullname != basename: - self._imported_module(node, fullname, relative) - - - def compute_module(self, context_name, mod_path): - """return true if the module should be added to dependencies""" - package_dir = dirname(self.project.path) - if context_name == mod_path: - return 0 - elif is_standard_module(mod_path, (package_dir,)): - return 1 - return 0 - - # protected methods ######################################################## - - def _imported_module(self, node, mod_path, relative): - """notify an imported module, used to analyze dependencies - """ - module = node.root() - context_name = module.name - if relative: - mod_path = '%s.%s' % ('.'.join(context_name.split('.')[:-1]), - mod_path) - if self.compute_module(context_name, mod_path): - # handle dependencies - if not hasattr(module, 'depends'): - module.depends = [] - mod_paths = module.depends - if not mod_path in mod_paths: - mod_paths.append(mod_path) diff -Nru astroid-1.0.1/manager.py astroid-1.3.8/manager.py --- astroid-1.0.1/manager.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/manager.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,303 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""astroid manager: avoid multiple astroid build of a same module when -possible by providing a class responsible to get astroid representation -from various source and using a cache of built modules) -""" - -__docformat__ = "restructuredtext en" - -import os -from os.path import dirname, join, isdir, exists - -from logilab.common.modutils import NoSourceFile, is_python_source, \ - file_from_modpath, load_module_from_name, modpath_from_file, \ - get_module_files, get_source_file, zipimport -from logilab.common.configuration import OptionsProviderMixIn - -from astroid.exceptions import AstroidBuildingException - -def astroid_wrapper(func, modname): - """wrapper to give to AstroidManager.project_from_files""" - print 'parsing %s...' % modname - try: - return func(modname) - except AstroidBuildingException, exc: - print exc - except Exception, exc: - import traceback - traceback.print_exc() - -def _silent_no_wrap(func, modname): - """silent wrapper that doesn't do anything; can be used for tests""" - return func(modname) - -def safe_repr(obj): - try: - return repr(obj) - except: - return '???' - - - -class AstroidManager(OptionsProviderMixIn): - """the astroid manager, responsible to build astroid from files - or modules. - - Use the Borg pattern. - """ - - name = 'astroid loader' - options = (("ignore", - {'type' : "csv", 'metavar' : "", - 'dest' : "black_list", "default" : ('CVS',), - 'help' : "add (may be a directory) to the black list\ -. It should be a base name, not a path. You may set this option multiple times\ -."}), - ("project", - {'default': "No Name", 'type' : 'string', 'short': 'p', - 'metavar' : '', - 'help' : 'set the project name.'}), - ) - brain = {} - def __init__(self): - self.__dict__ = AstroidManager.brain - if not self.__dict__: - OptionsProviderMixIn.__init__(self) - self.load_defaults() - # NOTE: cache entries are added by the [re]builder - self.astroid_cache = {} - self._mod_file_cache = {} - self.transforms = {} - - def ast_from_file(self, filepath, modname=None, fallback=True, source=False): - """given a module name, return the astroid object""" - try: - filepath = get_source_file(filepath, include_no_ext=True) - source = True - except NoSourceFile: - pass - if modname is None: - try: - modname = '.'.join(modpath_from_file(filepath)) - except ImportError: - modname = filepath - if modname in self.astroid_cache: - return self.astroid_cache[modname] - if source: - from astroid.builder import AstroidBuilder - return AstroidBuilder(self).file_build(filepath, modname) - elif fallback and modname: - return self.ast_from_module_name(modname) - raise AstroidBuildingException('unable to get astroid for file %s' % - filepath) - - def ast_from_module_name(self, modname, context_file=None): - """given a module name, return the astroid object""" - if modname in self.astroid_cache: - return self.astroid_cache[modname] - if modname == '__main__': - from astroid.builder import AstroidBuilder - return AstroidBuilder(self).string_build('', modname) - old_cwd = os.getcwd() - if context_file: - os.chdir(dirname(context_file)) - try: - filepath = self.file_from_module_name(modname, context_file) - if filepath is not None and not is_python_source(filepath): - module = self.zip_import_data(filepath) - if module is not None: - return module - if filepath is None or not is_python_source(filepath): - try: - module = load_module_from_name(modname) - except Exception, ex: - msg = 'Unable to load module %s (%s)' % (modname, ex) - raise AstroidBuildingException(msg) - return self.ast_from_module(module, modname) - return self.ast_from_file(filepath, modname, fallback=False) - finally: - os.chdir(old_cwd) - - def zip_import_data(self, filepath): - if zipimport is None: - return None - from astroid.builder import AstroidBuilder - builder = AstroidBuilder(self) - for ext in ('.zip', '.egg'): - try: - eggpath, resource = filepath.rsplit(ext + '/', 1) - except ValueError: - continue - try: - importer = zipimport.zipimporter(eggpath + ext) - zmodname = resource.replace('/', '.') - if importer.is_package(resource): - zmodname = zmodname + '.__init__' - module = builder.string_build(importer.get_source(resource), - zmodname, filepath) - return module - except: - continue - return None - - def file_from_module_name(self, modname, contextfile): - try: - value = self._mod_file_cache[(modname, contextfile)] - except KeyError: - try: - value = file_from_modpath(modname.split('.'), - context_file=contextfile) - except ImportError, ex: - msg = 'Unable to load module %s (%s)' % (modname, ex) - value = AstroidBuildingException(msg) - self._mod_file_cache[(modname, contextfile)] = value - if isinstance(value, AstroidBuildingException): - raise value - return value - - def ast_from_module(self, module, modname=None): - """given an imported module, return the astroid object""" - modname = modname or module.__name__ - if modname in self.astroid_cache: - return self.astroid_cache[modname] - try: - # some builtin modules don't have __file__ attribute - filepath = module.__file__ - if is_python_source(filepath): - return self.ast_from_file(filepath, modname) - except AttributeError: - pass - from astroid.builder import AstroidBuilder - return AstroidBuilder(self).module_build(module, modname) - - def ast_from_class(self, klass, modname=None): - """get astroid for the given class""" - if modname is None: - try: - modname = klass.__module__ - except AttributeError: - raise AstroidBuildingException( - 'Unable to get module for class %s' % safe_repr(klass)) - modastroid = self.ast_from_module_name(modname) - return modastroid.getattr(klass.__name__)[0] # XXX - - - def infer_ast_from_something(self, obj, context=None): - """infer astroid for the given class""" - if hasattr(obj, '__class__') and not isinstance(obj, type): - klass = obj.__class__ - else: - klass = obj - try: - modname = klass.__module__ - except AttributeError: - raise AstroidBuildingException( - 'Unable to get module for %s' % safe_repr(klass)) - except Exception, ex: - raise AstroidBuildingException( - 'Unexpected error while retrieving module for %s: %s' - % (safe_repr(klass), ex)) - try: - name = klass.__name__ - except AttributeError: - raise AstroidBuildingException( - 'Unable to get name for %s' % safe_repr(klass)) - except Exception, ex: - raise AstroidBuildingException( - 'Unexpected error while retrieving name for %s: %s' - % (safe_repr(klass), ex)) - # take care, on living object __module__ is regularly wrong :( - modastroid = self.ast_from_module_name(modname) - if klass is obj: - for infered in modastroid.igetattr(name, context): - yield infered - else: - for infered in modastroid.igetattr(name, context): - yield infered.instanciate_class() - - def project_from_files(self, files, func_wrapper=astroid_wrapper, - project_name=None, black_list=None): - """return a Project from a list of files or modules""" - # build the project representation - project_name = project_name or self.config.project - black_list = black_list or self.config.black_list - project = Project(project_name) - for something in files: - if not exists(something): - fpath = file_from_modpath(something.split('.')) - elif isdir(something): - fpath = join(something, '__init__.py') - else: - fpath = something - astroid = func_wrapper(self.ast_from_file, fpath) - if astroid is None: - continue - # XXX why is first file defining the project.path ? - project.path = project.path or astroid.file - project.add_module(astroid) - base_name = astroid.name - # recurse in package except if __init__ was explicitly given - if astroid.package and something.find('__init__') == -1: - # recurse on others packages / modules if this is a package - for fpath in get_module_files(dirname(astroid.file), - black_list): - astroid = func_wrapper(self.ast_from_file, fpath) - if astroid is None or astroid.name == base_name: - continue - project.add_module(astroid) - return project - - def register_transform(self, node_class, transform, predicate=None): - """Register `transform(node)` function to be applied on the given - Astroid's `node_class` if `predicate` is None or return a true value - when called with the node as argument. - - The transform function may return a value which is then used to - substitute the original node in the tree. - """ - self.transforms.setdefault(node_class, []).append( (transform, predicate) ) - -class Project: - """a project handle a set of modules / packages""" - def __init__(self, name=''): - self.name = name - self.path = None - self.modules = [] - self.locals = {} - self.__getitem__ = self.locals.__getitem__ - self.__iter__ = self.locals.__iter__ - self.values = self.locals.values - self.keys = self.locals.keys - self.items = self.locals.items - - def add_module(self, node): - self.locals[node.name] = node - self.modules.append(node) - - def get_module(self, name): - return self.locals[name] - - def get_children(self): - return self.modules - - def __repr__(self): - return '' % (self.name, id(self), - len(self.modules)) - - diff -Nru astroid-1.0.1/MANIFEST.in astroid-1.3.8/MANIFEST.in --- astroid-1.0.1/MANIFEST.in 2013-07-29 15:04:24.000000000 +0000 +++ astroid-1.3.8/MANIFEST.in 2015-03-09 22:00:27.000000000 +0000 @@ -1,9 +1,7 @@ include ChangeLog -include README* +include README include COPYING include COPYING.LESSER -include test/fulltest.sh -recursive-include test/data *.py *.zip *.egg -recursive-include test/data2 *.py -recursive-include test/regrtest_data *.py -recursive-include brain *.py +include tox.ini +recursive-include astroid/tests/testdata *.py *.zip *.egg +recursive-include astroid/brain *.py diff -Nru astroid-1.0.1/mixins.py astroid-1.3.8/mixins.py --- astroid-1.0.1/mixins.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/mixins.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""This module contains some mixins for the different nodes. -""" - -from astroid.exceptions import (AstroidBuildingException, InferenceError, - NotFoundError) - - -class BlockRangeMixIn(object): - """override block range """ - def set_line_info(self, lastchild): - self.fromlineno = self.lineno - self.tolineno = lastchild.tolineno - self.blockstart_tolineno = self._blockstart_toline() - - def _elsed_block_range(self, lineno, orelse, last=None): - """handle block line numbers range for try/finally, for, if and while - statements - """ - if lineno == self.fromlineno: - return lineno, lineno - if orelse: - if lineno >= orelse[0].fromlineno: - return lineno, orelse[-1].tolineno - return lineno, orelse[0].fromlineno - 1 - return lineno, last or self.tolineno - - -class FilterStmtsMixin(object): - """Mixin for statement filtering and assignment type""" - - def _get_filtered_stmts(self, _, node, _stmts, mystmt): - """method used in _filter_stmts to get statemtents and trigger break""" - if self.statement() is mystmt: - # original node's statement is the assignment, only keep - # current node (gen exp, list comp) - return [node], True - return _stmts, False - - def ass_type(self): - return self - - -class AssignTypeMixin(object): - - def ass_type(self): - return self - - def _get_filtered_stmts(self, lookup_node, node, _stmts, mystmt): - """method used in filter_stmts""" - if self is mystmt: - return _stmts, True - if self.statement() is mystmt: - # original node's statement is the assignment, only keep - # current node (gen exp, list comp) - return [node], True - return _stmts, False - - -class ParentAssignTypeMixin(AssignTypeMixin): - - def ass_type(self): - return self.parent.ass_type() - - -class FromImportMixIn(FilterStmtsMixin): - """MixIn for From and Import Nodes""" - - def _infer_name(self, frame, name): - return name - - def do_import_module(self, modname): - """return the ast for a module whose name is imported by - """ - # handle special case where we are on a package node importing a module - # using the same name as the package, which may end in an infinite loop - # on relative imports - # XXX: no more needed ? - mymodule = self.root() - level = getattr(self, 'level', None) # Import as no level - # XXX we should investigate deeper if we really want to check - # importing itself: modname and mymodule.name be relative or absolute - if mymodule.relative_to_absolute_name(modname, level) == mymodule.name: - # FIXME: we used to raise InferenceError here, but why ? - return mymodule - try: - return mymodule.import_module(modname, level=level) - except AstroidBuildingException: - raise InferenceError(modname) - except SyntaxError, ex: - raise InferenceError(str(ex)) - - def real_name(self, asname): - """get name from 'as' name""" - for name, _asname in self.names: - if name == '*': - return asname - if not _asname: - name = name.split('.', 1)[0] - _asname = name - if asname == _asname: - return name - raise NotFoundError(asname) - - - diff -Nru astroid-1.0.1/node_classes.py astroid-1.3.8/node_classes.py --- astroid-1.0.1/node_classes.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/node_classes.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,925 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""Module for some node classes. More nodes in scoped_nodes.py -""" - -import sys - -from astroid.exceptions import NoDefault -from astroid.bases import (NodeNG, Statement, Instance, InferenceContext, - _infer_stmts, YES, BUILTINS) -from astroid.mixins import BlockRangeMixIn, AssignTypeMixin, \ - ParentAssignTypeMixin, FromImportMixIn - - -def unpack_infer(stmt, context=None): - """recursively generate nodes inferred by the given statement. - If the inferred value is a list or a tuple, recurse on the elements - """ - if isinstance(stmt, (List, Tuple)): - for elt in stmt.elts: - for infered_elt in unpack_infer(elt, context): - yield infered_elt - return - # if infered is a final node, return it and stop - infered = stmt.infer(context).next() - if infered is stmt: - yield infered - return - # else, infer recursivly, except YES object that should be returned as is - for infered in stmt.infer(context): - if infered is YES: - yield infered - else: - for inf_inf in unpack_infer(infered, context): - yield inf_inf - - -def are_exclusive(stmt1, stmt2, exceptions=None): - """return true if the two given statements are mutually exclusive - - `exceptions` may be a list of exception names. If specified, discard If - branches and check one of the statement is in an exception handler catching - one of the given exceptions. - - algorithm : - 1) index stmt1's parents - 2) climb among stmt2's parents until we find a common parent - 3) if the common parent is a If or TryExcept statement, look if nodes are - in exclusive branches - """ - # index stmt1's parents - stmt1_parents = {} - children = {} - node = stmt1.parent - previous = stmt1 - while node: - stmt1_parents[node] = 1 - children[node] = previous - previous = node - node = node.parent - # climb among stmt2's parents until we find a common parent - node = stmt2.parent - previous = stmt2 - while node: - if node in stmt1_parents: - # if the common parent is a If or TryExcept statement, look if - # nodes are in exclusive branches - if isinstance(node, If) and exceptions is None: - if (node.locate_child(previous)[1] - is not node.locate_child(children[node])[1]): - return True - elif isinstance(node, TryExcept): - c2attr, c2node = node.locate_child(previous) - c1attr, c1node = node.locate_child(children[node]) - if c1node is not c2node: - if ((c2attr == 'body' and c1attr == 'handlers' and children[node].catch(exceptions)) or - (c2attr == 'handlers' and c1attr == 'body' and previous.catch(exceptions)) or - (c2attr == 'handlers' and c1attr == 'orelse') or - (c2attr == 'orelse' and c1attr == 'handlers')): - return True - elif c2attr == 'handlers' and c1attr == 'handlers': - return previous is not children[node] - return False - previous = node - node = node.parent - return False - - -class LookupMixIn(object): - """Mixin looking up a name in the right scope - """ - - def lookup(self, name): - """lookup a variable name - - return the scope node and the list of assignments associated to the given - name according to the scope where it has been found (locals, globals or - builtin) - - The lookup is starting from self's scope. If self is not a frame itself and - the name is found in the inner frame locals, statements will be filtered - to remove ignorable statements according to self's location - """ - return self.scope().scope_lookup(self, name) - - def ilookup(self, name): - """infered lookup - - return an iterator on infered values of the statements returned by - the lookup method - """ - frame, stmts = self.lookup(name) - context = InferenceContext() - return _infer_stmts(stmts, context, frame) - - def _filter_stmts(self, stmts, frame, offset): - """filter statements to remove ignorable statements. - - If self is not a frame itself and the name is found in the inner - frame locals, statements will be filtered to remove ignorable - statements according to self's location - """ - # if offset == -1, my actual frame is not the inner frame but its parent - # - # class A(B): pass - # - # we need this to resolve B correctly - if offset == -1: - myframe = self.frame().parent.frame() - else: - myframe = self.frame() - if not myframe is frame or self is frame: - return stmts - mystmt = self.statement() - # line filtering if we are in the same frame - # - # 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 - mylineno = 0 - _stmts = [] - _stmt_parents = [] - 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: - break - assert hasattr(node, 'ass_type'), (node, node.scope(), - node.scope().locals) - ass_type = node.ass_type() - - if node.has_base(self): - break - - _stmts, done = ass_type._get_filtered_stmts(self, node, _stmts, mystmt) - if done: - break - - optional_assign = ass_type.optional_assign - if optional_assign and ass_type.parent_of(self): - # we are inside a loop, loop var assigment is hidding previous - # assigment - _stmts = [node] - _stmt_parents = [stmt.parent] - continue - - # XXX comment various branches below!!! - try: - pindex = _stmt_parents.index(stmt.parent) - except ValueError: - pass - else: - # we got a parent index, this means the currently visited node - # is at the same block level as a previously visited node - if _stmts[pindex].ass_type().parent_of(ass_type): - # both statements are not at the same block level - continue - # if currently visited node is following previously considered - # assignement and both are not exclusive, we can drop the - # previous one. For instance in the following code :: - # - # if a: - # x = 1 - # else: - # x = 2 - # print x - # - # we can't remove neither x = 1 nor x = 2 when looking for 'x' - # of 'print x'; while in the following :: - # - # x = 1 - # x = 2 - # print x - # - # we can remove x = 1 when we see x = 2 - # - # moreover, on loop assignment types, assignment won't - # necessarily be done if the loop has no iteration, so we don't - # want to clear previous assigments if any (hence the test on - # optional_assign) - if not (optional_assign or are_exclusive(_stmts[pindex], node)): - del _stmt_parents[pindex] - del _stmts[pindex] - if isinstance(node, AssName): - if not optional_assign and stmt.parent is mystmt.parent: - _stmts = [] - _stmt_parents = [] - elif isinstance(node, DelName): - _stmts = [] - _stmt_parents = [] - continue - if not are_exclusive(self, node): - _stmts.append(node) - _stmt_parents.append(stmt.parent) - return _stmts - -# Name classes - -class AssName(LookupMixIn, ParentAssignTypeMixin, NodeNG): - """class representing an AssName node""" - - -class DelName(LookupMixIn, ParentAssignTypeMixin, NodeNG): - """class representing a DelName node""" - - -class Name(LookupMixIn, NodeNG): - """class representing a Name node""" - - - - -##################### node classes ######################################## - -class Arguments(NodeNG, AssignTypeMixin): - """class representing an Arguments node""" - _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 - self.kwarg = kwarg - - def _infer_name(self, frame, name): - if self.parent is frame: - return name - return None - - def format_args(self): - """return arguments formatted as string""" - result = [] - if self.args: - result.append(_format_args(self.args, self.defaults)) - if self.vararg: - 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): - """return the default value for an argument - - :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] - raise NoDefault() - - def is_argument(self, name): - """return True if the name is defined in arguments""" - if name == self.vararg: - return True - if name == self.kwarg: - 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) - 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): - if isinstance(arg, Tuple): - if rec: - found = _find_arg(argname, arg.elts) - if found[0] is not None: - return found - elif arg.name == argname: - return i, arg - return None, None - - -def _format_args(args, defaults=None): - values = [] - if args is None: - return '' - if defaults is not None: - default_offset = len(args) - len(defaults) - for i, arg in enumerate(args): - if isinstance(arg, Tuple): - values.append('(%s)' % _format_args(arg.elts)) - else: - values.append(arg.name) - 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) - - -class AssAttr(NodeNG, ParentAssignTypeMixin): - """class representing an AssAttr node""" - _astroid_fields = ('expr',) - expr = None - -class Assert(Statement): - """class representing an Assert node""" - _astroid_fields = ('test', 'fail',) - test = None - fail = None - -class Assign(Statement, AssignTypeMixin): - """class representing an Assign node""" - _astroid_fields = ('targets', 'value',) - targets = None - value = None - -class AugAssign(Statement, AssignTypeMixin): - """class representing an AugAssign node""" - _astroid_fields = ('target', 'value',) - target = None - value = None - -class Backquote(NodeNG): - """class representing a Backquote node""" - _astroid_fields = ('value',) - value = None - -class BinOp(NodeNG): - """class representing a BinOp node""" - _astroid_fields = ('left', 'right',) - left = None - right = None - -class BoolOp(NodeNG): - """class representing a BoolOp node""" - _astroid_fields = ('values',) - values = None - -class Break(Statement): - """class representing a Break node""" - - -class CallFunc(NodeNG): - """class representing a CallFunc node""" - _astroid_fields = ('func', 'args', 'starargs', 'kwargs') - func = None - args = None - starargs = None - kwargs = None - - def __init__(self): - self.starargs = None - self.kwargs = None - -class Compare(NodeNG): - """class representing a Compare node""" - _astroid_fields = ('left', 'ops',) - left = None - ops = None - - def get_children(self): - """override get_children for tuple fields""" - yield self.left - for _, comparator in self.ops: - yield comparator # we don't want the 'op' - - def last_child(self): - """override last_child""" - # XXX maybe if self.ops: - return self.ops[-1][1] - #return self.left - -class Comprehension(NodeNG): - """class representing a Comprehension node""" - _astroid_fields = ('target', 'iter' ,'ifs') - target = None - iter = None - ifs = None - - optional_assign = True - def ass_type(self): - return self - - def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt): - """method used in filter_stmts""" - if self is mystmt: - if isinstance(lookup_node, (Const, Name)): - return [lookup_node], True - - elif self.statement() is mystmt: - # original node's statement is the assignment, only keeps - # current node (gen exp, list comp) - - return [node], True - - return stmts, False - - -class Const(NodeNG, Instance): - """represent a constant node like num, str, bool, None, bytes""" - - def __init__(self, value=None): - self.value = value - - def getitem(self, index, context=None): - if isinstance(self.value, basestring): - return Const(self.value[index]) - raise TypeError('%r (value=%s)' % (self, self.value)) - - def has_dynamic_getattr(self): - return False - - def itered(self): - if isinstance(self.value, basestring): - return self.value - raise TypeError() - - def pytype(self): - return self._proxied.qname() - - -class Continue(Statement): - """class representing a Continue node""" - - -class Decorators(NodeNG): - """class representing a Decorators node""" - _astroid_fields = ('nodes',) - nodes = None - - def __init__(self, nodes=None): - self.nodes = nodes - - def scope(self): - # skip the function node to go directly to the upper level scope - return self.parent.parent.scope() - -class DelAttr(NodeNG, ParentAssignTypeMixin): - """class representing a DelAttr node""" - _astroid_fields = ('expr',) - expr = None - - -class Delete(Statement, AssignTypeMixin): - """class representing a Delete node""" - _astroid_fields = ('targets',) - targets = None - - -class Dict(NodeNG, Instance): - """class representing a Dict node""" - _astroid_fields = ('items',) - - def __init__(self, items=None): - if items is None: - self.items = [] - else: - self.items = [(const_factory(k), const_factory(v)) - for k,v in items.iteritems()] - - def pytype(self): - return '%s.dict' % BUILTINS - - def get_children(self): - """get children of a Dict node""" - # overrides get_children - for key, value in self.items: - yield key - yield value - - def last_child(self): - """override last_child""" - if self.items: - return self.items[-1][1] - return None - - def itered(self): - return self.items[::2] - - def getitem(self, lookup_key, context=None): - for key, value in self.items: - for inferedkey in key.infer(context): - if inferedkey is YES: - continue - if isinstance(inferedkey, Const) and inferedkey.value == lookup_key: - return value - # This should raise KeyError, but all call sites only catch - # IndexError. Let's leave it like that for now. - raise IndexError(lookup_key) - - -class Discard(Statement): - """class representing a Discard node""" - _astroid_fields = ('value',) - value = None - - -class Ellipsis(NodeNG): - """class representing an Ellipsis node""" - - -class EmptyNode(NodeNG): - """class representing an EmptyNode node""" - - -class ExceptHandler(Statement, AssignTypeMixin): - """class representing an ExceptHandler node""" - _astroid_fields = ('type', 'name', 'body',) - type = None - name = None - body = None - - def _blockstart_toline(self): - if self.name: - return self.name.tolineno - elif self.type: - return self.type.tolineno - else: - return self.lineno - - def set_line_info(self, lastchild): - self.fromlineno = self.lineno - self.tolineno = lastchild.tolineno - self.blockstart_tolineno = self._blockstart_toline() - - def catch(self, exceptions): - if self.type is None or exceptions is None: - return True - for node in self.type.nodes_of_class(Name): - if node.name in exceptions: - return True - - -class Exec(Statement): - """class representing an Exec node""" - _astroid_fields = ('expr', 'globals', 'locals',) - expr = None - globals = None - locals = None - - -class ExtSlice(NodeNG): - """class representing an ExtSlice node""" - _astroid_fields = ('dims',) - dims = None - -class For(BlockRangeMixIn, AssignTypeMixin, Statement): - """class representing a For node""" - _astroid_fields = ('target', 'iter', 'body', 'orelse',) - target = None - iter = None - body = None - orelse = None - - optional_assign = True - def _blockstart_toline(self): - return self.iter.tolineno - - -class From(FromImportMixIn, Statement): - """class representing a From node""" - - def __init__(self, fromname, names, level=0): - self.modname = fromname - self.names = names - self.level = level - -class Getattr(NodeNG): - """class representing a Getattr node""" - _astroid_fields = ('expr',) - expr = None - - -class Global(Statement): - """class representing a Global node""" - - def __init__(self, names): - self.names = names - - def _infer_name(self, frame, name): - return name - - -class If(BlockRangeMixIn, Statement): - """class representing an If node""" - _astroid_fields = ('test', 'body', 'orelse') - test = None - body = None - orelse = None - - def _blockstart_toline(self): - return self.test.tolineno - - def block_range(self, lineno): - """handle block line numbers range for if statements""" - if lineno == self.body[0].fromlineno: - return lineno, lineno - if lineno <= self.body[-1].tolineno: - return lineno, self.body[-1].tolineno - return self._elsed_block_range(lineno, self.orelse, - self.body[0].fromlineno - 1) - - -class IfExp(NodeNG): - """class representing an IfExp node""" - _astroid_fields = ('test', 'body', 'orelse') - test = None - body = None - orelse = None - - -class Import(FromImportMixIn, Statement): - """class representing an Import node""" - - -class Index(NodeNG): - """class representing an Index node""" - _astroid_fields = ('value',) - value = None - - -class Keyword(NodeNG): - """class representing a Keyword node""" - _astroid_fields = ('value',) - value = None - - -class List(NodeNG, Instance, ParentAssignTypeMixin): - """class representing a List node""" - _astroid_fields = ('elts',) - - def __init__(self, elts=None): - if elts is None: - self.elts = [] - else: - self.elts = [const_factory(e) for e in elts] - - def pytype(self): - return '%s.list' % BUILTINS - - def getitem(self, index, context=None): - return self.elts[index] - - def itered(self): - return self.elts - - -class Nonlocal(Statement): - """class representing a Nonlocal node""" - - def __init__(self, names): - self.names = names - - def _infer_name(self, frame, name): - return name - - -class Pass(Statement): - """class representing a Pass node""" - - -class Print(Statement): - """class representing a Print node""" - _astroid_fields = ('dest', 'values',) - dest = None - values = None - - -class Raise(Statement): - """class representing a Raise node""" - exc = None - if sys.version_info < (3, 0): - _astroid_fields = ('exc', 'inst', 'tback') - inst = None - tback = None - else: - _astroid_fields = ('exc', 'cause') - exc = None - cause = None - - def raises_not_implemented(self): - if not self.exc: - return - for name in self.exc.nodes_of_class(Name): - if name.name == 'NotImplementedError': - return True - - -class Return(Statement): - """class representing a Return node""" - _astroid_fields = ('value',) - value = None - - -class Set(NodeNG, Instance, ParentAssignTypeMixin): - """class representing a Set node""" - _astroid_fields = ('elts',) - - def __init__(self, elts=None): - if elts is None: - self.elts = [] - else: - self.elts = [const_factory(e) for e in elts] - - def pytype(self): - return '%s.set' % BUILTINS - - def itered(self): - return self.elts - - -class Slice(NodeNG): - """class representing a Slice node""" - _astroid_fields = ('lower', 'upper', 'step') - lower = None - upper = None - step = None - -class Starred(NodeNG, ParentAssignTypeMixin): - """class representing a Starred node""" - _astroid_fields = ('value',) - value = None - - -class Subscript(NodeNG): - """class representing a Subscript node""" - _astroid_fields = ('value', 'slice') - value = None - slice = None - - -class TryExcept(BlockRangeMixIn, Statement): - """class representing a TryExcept node""" - _astroid_fields = ('body', 'handlers', 'orelse',) - body = None - handlers = None - orelse = None - - def _infer_name(self, frame, name): - return name - - def _blockstart_toline(self): - return self.lineno - - def block_range(self, lineno): - """handle block line numbers range for try/except statements""" - last = None - for exhandler in self.handlers: - if exhandler.type and lineno == exhandler.type.fromlineno: - return lineno, lineno - if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: - return lineno, exhandler.body[-1].tolineno - if last is None: - last = exhandler.body[0].fromlineno - 1 - return self._elsed_block_range(lineno, self.orelse, last) - - -class TryFinally(BlockRangeMixIn, Statement): - """class representing a TryFinally node""" - _astroid_fields = ('body', 'finalbody',) - body = None - finalbody = None - - def _blockstart_toline(self): - return self.lineno - - def block_range(self, lineno): - """handle block line numbers range for try/finally statements""" - child = self.body[0] - # py2.5 try: except: finally: - if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno - and lineno > self.fromlineno and lineno <= child.tolineno): - return child.block_range(lineno) - return self._elsed_block_range(lineno, self.finalbody) - - -class Tuple(NodeNG, Instance, ParentAssignTypeMixin): - """class representing a Tuple node""" - _astroid_fields = ('elts',) - - def __init__(self, elts=None): - if elts is None: - self.elts = [] - else: - self.elts = [const_factory(e) for e in elts] - - def pytype(self): - return '%s.tuple' % BUILTINS - - def getitem(self, index, context=None): - return self.elts[index] - - def itered(self): - return self.elts - - -class UnaryOp(NodeNG): - """class representing an UnaryOp node""" - _astroid_fields = ('operand',) - operand = None - - -class While(BlockRangeMixIn, Statement): - """class representing a While node""" - _astroid_fields = ('test', 'body', 'orelse',) - test = None - body = None - orelse = None - - def _blockstart_toline(self): - return self.test.tolineno - - def block_range(self, lineno): - """handle block line numbers range for for and while statements""" - return self. _elsed_block_range(lineno, self.orelse) - - -class With(BlockRangeMixIn, AssignTypeMixin, Statement): - """class representing a With node""" - _astroid_fields = ('items', 'body') - items = None - body = None - - def _blockstart_toline(self): - return self.items[-1][0].tolineno - - def get_children(self): - for expr, var in self.items: - yield expr - if var: - yield var - for elt in self.body: - yield elt - -class Yield(NodeNG): - """class representing a Yield node""" - _astroid_fields = ('value',) - value = None - -# constants ############################################################## - -CONST_CLS = { - list: List, - tuple: Tuple, - dict: Dict, - set: Set, - type(None): Const, - } - -def _update_const_classes(): - """update constant classes, so the keys of CONST_CLS can be reused""" - klasses = (bool, int, float, complex, str) - if sys.version_info < (3, 0): - klasses += (unicode, long) - if sys.version_info >= (2, 6): - klasses += (bytes,) - for kls in klasses: - CONST_CLS[kls] = Const -_update_const_classes() - -def const_factory(value): - """return an astroid node for a python value""" - # XXX we should probably be stricter here and only consider stuff in - # CONST_CLS or do better treatment: in case where value is not in CONST_CLS, - # we should rather recall the builder on this value than returning an empty - # node (another option being that const_factory shouldn't be called with something - # not in CONST_CLS) - assert not isinstance(value, NodeNG) - try: - return CONST_CLS[value.__class__](value) - except (KeyError, AttributeError): - node = EmptyNode() - node.object = value - return node diff -Nru astroid-1.0.1/nodes.py astroid-1.3.8/nodes.py --- astroid-1.0.1/nodes.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/nodes.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -""" -on all nodes : - .is_statement, returning true if the node should be considered as a - statement node - .root(), returning the root node of the tree (i.e. a Module) - .previous_sibling(), returning previous sibling statement node - .next_sibling(), returning next sibling statement node - .statement(), returning the first parent node marked as statement node - .frame(), returning the first node defining a new local scope (i.e. - Module, Function or Class) - .set_local(name, node), define an identifier on the first parent frame, - with the node defining it. This is used by the astroid builder and should not - be used from out there. - -on From and Import : - .real_name(name), - - -""" - -__docformat__ = "restructuredtext en" - -from astroid.node_classes import Arguments, AssAttr, Assert, Assign, \ - AssName, AugAssign, Backquote, BinOp, BoolOp, Break, CallFunc, Compare, \ - Comprehension, Const, Continue, Decorators, DelAttr, DelName, Delete, \ - Dict, Discard, Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, For, \ - From, Getattr, Global, If, IfExp, Import, Index, Keyword, \ - List, Name, Nonlocal, Pass, Print, Raise, Return, Set, Slice, Starred, Subscript, \ - TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, \ - const_factory -from astroid.scoped_nodes import Module, GenExpr, Lambda, DictComp, \ - ListComp, SetComp, Function, Class - -ALL_NODE_CLASSES = ( - Arguments, AssAttr, Assert, Assign, AssName, AugAssign, - Backquote, BinOp, BoolOp, Break, - CallFunc, Class, Compare, Comprehension, Const, Continue, - Decorators, DelAttr, DelName, Delete, - Dict, DictComp, Discard, - Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, - For, From, Function, - Getattr, GenExpr, Global, - If, IfExp, Import, Index, - Keyword, - Lambda, List, ListComp, - Name, Nonlocal, - Module, - Pass, Print, - Raise, Return, - Set, SetComp, Slice, Starred, Subscript, - TryExcept, TryFinally, Tuple, - UnaryOp, - While, With, - Yield, - ) - diff -Nru astroid-1.0.1/PKG-INFO astroid-1.3.8/PKG-INFO --- astroid-1.0.1/PKG-INFO 2013-10-18 15:34:22.000000000 +0000 +++ astroid-1.3.8/PKG-INFO 2015-08-02 20:40:06.000000000 +0000 @@ -1,71 +1,80 @@ -Metadata-Version: 1.1 -Name: astroid -Version: 1.0.1 -Summary: rebuild a new abstract syntax tree from Python's ast -Home-page: http://bitbucket.org/logilab/astroid -Author: Logilab -Author-email: python-projects@lists.logilab.org -License: LGPL -Description: Astroid - ======= - - What's this? - ------------ - - The aim of this module is to provide a common base representation of - python source code for projects such as pychecker, pyreverse, - pylint... Well, actually the development of this library is essentially - governed by pylint's needs. It used to be called logilab-astng. - - It provides a compatible representation which comes from the `_ast` - module. It rebuilds the tree generated by the builtin _ast module by - recursively walking down the AST and building an extended ast. The new - node classes have additional methods and attributes for different - usages. They include some support for static inference and local name - scopes. Furthermore, astroid builds partial trees by inspecting living - objects. - - Main modules are: - - * `bases`, `node_classses` and `scoped_nodes` contain the classes for the - different type of nodes of the tree. - - * the `manager` contains a high level object to get astroid trees from - source files and living objects. It maintains a cache of previously - constructed tree for quick access. - - - Installation - ------------ - - Extract the tarball, jump into the created directory and run:: - - python setup.py install - - For installation options, see:: - - python setup.py install --help - - - If you have any questions, please mail the code-quality@python.org - mailing list for support. See - http://mail.python.org/mailman/listinfo/code-quality for subscription - information and archives. You may find older archives at - http://lists.logilab.org/mailman/listinfo/python-projects . - - Test - ---- - - Tests are in the 'test' subdirectory. To launch the whole tests suite - at once, you may use the 'pytest' utility from logilab-common (simply - type 'pytest' from within this directory) or if you're running python - >= 2.7, using discover, for instance:: - - python -m unittest discover -p "unittest*.py" - -Platform: UNKNOWN -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Software Development :: Quality Assurance -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 +Metadata-Version: 1.1 +Name: astroid +Version: 1.3.8 +Summary: A abstract syntax tree for Python with inference support. +Home-page: http://bitbucket.org/logilab/astroid +Author: Logilab +Author-email: pylint-dev@lists.logilab.org +License: LGPL +Description: .. image:: https://drone.io/bitbucket.org/logilab/astroid/status.png + :alt: drone.io Build Status + :target: https://drone.io/bitbucket.org/logilab/astroid + + Astroid + ======= + + What's this? + ------------ + + The aim of this module is to provide a common base representation of + python source code for projects such as pychecker, pyreverse, + pylint... Well, actually the development of this library is essentially + governed by pylint's needs. It used to be called logilab-astng. + + It provides a compatible representation which comes from the `_ast` + module. It rebuilds the tree generated by the builtin _ast module by + recursively walking down the AST and building an extended ast. The new + node classes have additional methods and attributes for different + usages. They include some support for static inference and local name + scopes. Furthermore, astroid builds partial trees by inspecting living + objects. + + Main modules are: + + * `bases`, `node_classses` and `scoped_nodes` contain the classes for the + different type of nodes of the tree. + + * the `manager` contains a high level object to get astroid trees from + source files and living objects. It maintains a cache of previously + constructed tree for quick access. + + + Installation + ------------ + + Extract the tarball, jump into the created directory and run:: + + python setup.py install + + For installation options, see:: + + python setup.py install --help + + + If you have any questions, please mail the code-quality@python.org + mailing list for support. See + http://mail.python.org/mailman/listinfo/code-quality for subscription + information and archives. You may find older archives at + http://lists.logilab.org/mailman/listinfo/python-projects . + + Python Versions + --------------- + + astroid is compatible with Python 2.7 as well as 3.3 and later. astroid uses + the same code base for both Python versions, using six. + + Test + ---- + + Tests are in the 'test' subdirectory. To launch the whole tests suite + at once, you may use the 'pytest' utility from logilab-common (simply + type 'pytest' from within this directory) or using unittest discover:: + + python -m unittest discover -p "unittest*.py" + +Platform: UNKNOWN +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 diff -Nru astroid-1.0.1/__pkginfo__.py astroid-1.3.8/__pkginfo__.py --- astroid-1.0.1/__pkginfo__.py 2013-10-18 15:34:05.000000000 +0000 +++ astroid-1.3.8/__pkginfo__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""astroid packaging information""" - -distname = 'astroid' - -modname = 'astroid' - -numversion = (1, 0, 1) -version = '.'.join([str(num) for num in numversion]) - -install_requires = ['logilab-common >= 0.60.0'] - -license = 'LGPL' - -author = 'Logilab' -author_email = 'python-projects@lists.logilab.org' -mailinglist = "mailto://%s" % author_email -web = 'http://bitbucket.org/logilab/astroid' - -description = "rebuild a new abstract syntax tree from Python's ast" - -from os.path import join -include_dirs = ['brain', - join('test', 'regrtest_data'), - join('test', 'data'), join('test', 'data2')] - -classifiers = ["Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Software Development :: Quality Assurance", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 3", - ] diff -Nru astroid-1.0.1/protocols.py astroid-1.3.8/protocols.py --- astroid-1.0.1/protocols.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/protocols.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,320 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""this module contains a set of functions to handle python protocols for nodes -where it makes sense. -""" - -__doctype__ = "restructuredtext en" - -from astroid.exceptions import InferenceError, NoDefault -from astroid.node_classes import unpack_infer -from astroid.bases import copy_context, \ - raise_if_nothing_infered, yes_if_nothing_infered, Instance, YES -from astroid.nodes import const_factory -from astroid import nodes - -# unary operations ############################################################ - -def tl_infer_unary_op(self, operator): - if operator == 'not': - return const_factory(not bool(self.elts)) - raise TypeError() # XXX log unsupported operation -nodes.Tuple.infer_unary_op = tl_infer_unary_op -nodes.List.infer_unary_op = tl_infer_unary_op - - -def dict_infer_unary_op(self, operator): - if operator == 'not': - return const_factory(not bool(self.items)) - raise TypeError() # XXX log unsupported operation -nodes.Dict.infer_unary_op = dict_infer_unary_op - - -def const_infer_unary_op(self, operator): - if operator == 'not': - return const_factory(not self.value) - # XXX log potentially raised TypeError - elif operator == '+': - return const_factory(+self.value) - else: # operator == '-': - return const_factory(-self.value) -nodes.Const.infer_unary_op = const_infer_unary_op - - -# binary operations ########################################################### - -BIN_OP_IMPL = {'+': lambda a, b: a + b, - '-': lambda a, b: a - b, - '/': lambda a, b: a / b, - '//': lambda a, b: a // b, - '*': lambda a, b: a * b, - '**': lambda a, b: a ** b, - '%': lambda a, b: a % b, - '&': lambda a, b: a & b, - '|': lambda a, b: a | b, - '^': lambda a, b: a ^ b, - '<<': lambda a, b: a << b, - '>>': lambda a, b: a >> b, - } -for key, impl in BIN_OP_IMPL.items(): - BIN_OP_IMPL[key+'='] = impl - -def const_infer_binary_op(self, operator, other, context): - for other in other.infer(context): - if isinstance(other, nodes.Const): - try: - impl = BIN_OP_IMPL[operator] - - try: - yield const_factory(impl(self.value, other.value)) - except Exception: - # ArithmeticError is not enough: float >> float is a TypeError - # TODO : let pylint know about the problem - pass - except TypeError: - # XXX log TypeError - continue - elif other is YES: - yield other - else: - try: - for val in other.infer_binary_op(operator, self, context): - yield val - except AttributeError: - yield YES -nodes.Const.infer_binary_op = yes_if_nothing_infered(const_infer_binary_op) - - -def tl_infer_binary_op(self, operator, other, context): - for other in other.infer(context): - if isinstance(other, self.__class__) and operator == '+': - node = self.__class__() - elts = [n for elt in self.elts for n in elt.infer(context) - if not n is YES] - elts += [n for elt in other.elts for n in elt.infer(context) - if not n is YES] - node.elts = elts - yield node - elif isinstance(other, nodes.Const) and operator == '*': - if not isinstance(other.value, int): - yield YES - continue - node = self.__class__() - elts = [n for elt in self.elts for n in elt.infer(context) - if not n is YES] * other.value - node.elts = elts - yield node - elif isinstance(other, Instance) and not isinstance(other, nodes.Const): - yield YES - # XXX else log TypeError -nodes.Tuple.infer_binary_op = yes_if_nothing_infered(tl_infer_binary_op) -nodes.List.infer_binary_op = yes_if_nothing_infered(tl_infer_binary_op) - - -def dict_infer_binary_op(self, operator, other, context): - for other in other.infer(context): - if isinstance(other, Instance) and isinstance(other._proxied, nodes.Class): - yield YES - # XXX else log TypeError -nodes.Dict.infer_binary_op = yes_if_nothing_infered(dict_infer_binary_op) - - -# assignment ################################################################## - -"""the assigned_stmts method is responsible to return the assigned statement -(e.g. not inferred) according to the assignment type. - -The `asspath` argument is used to record the lhs path of the original node. -For instance if we want assigned statements for 'c' in 'a, (b,c)', asspath -will be [1, 1] once arrived to the Assign node. - -The `context` argument is the current inference context which should be given -to any intermediary inference necessary. -""" - -def _resolve_looppart(parts, asspath, context): - """recursive function to resolve multiple assignments on loops""" - asspath = asspath[:] - index = asspath.pop(0) - for part in parts: - if part is YES: - continue - # XXX handle __iter__ and log potentially detected errors - if not hasattr(part, 'itered'): - continue - try: - itered = part.itered() - except TypeError: - continue # XXX log error - for stmt in itered: - try: - assigned = stmt.getitem(index, context) - except (AttributeError, IndexError): - continue - except TypeError, exc: # stmt is unsubscriptable Const - continue - if not asspath: - # we achieved to resolved the assignment path, - # don't infer the last part - yield assigned - elif assigned is YES: - break - else: - # we are not yet on the last part of the path - # search on each possibly inferred value - try: - for infered in _resolve_looppart(assigned.infer(context), - asspath, context): - yield infered - except InferenceError: - break - - -def for_assigned_stmts(self, node, context=None, asspath=None): - if asspath is None: - for lst in self.iter.infer(context): - if isinstance(lst, (nodes.Tuple, nodes.List)): - for item in lst.elts: - yield item - else: - for infered in _resolve_looppart(self.iter.infer(context), - asspath, context): - yield infered - -nodes.For.assigned_stmts = raise_if_nothing_infered(for_assigned_stmts) -nodes.Comprehension.assigned_stmts = raise_if_nothing_infered(for_assigned_stmts) - - -def mulass_assigned_stmts(self, node, context=None, asspath=None): - if asspath is None: - asspath = [] - asspath.insert(0, self.elts.index(node)) - return self.parent.assigned_stmts(self, context, asspath) -nodes.Tuple.assigned_stmts = mulass_assigned_stmts -nodes.List.assigned_stmts = mulass_assigned_stmts - - -def assend_assigned_stmts(self, context=None): - return self.parent.assigned_stmts(self, context=context) -nodes.AssName.assigned_stmts = assend_assigned_stmts -nodes.AssAttr.assigned_stmts = assend_assigned_stmts - - -def _arguments_infer_argname(self, name, context): - # arguments information may be missing, in which case we can't do anything - # more - if not (self.args or self.vararg or self.kwarg): - yield YES - return - # first argument of instance/class method - if self.args and getattr(self.args[0], 'name', None) == name: - functype = self.parent.type - if functype == 'method': - yield Instance(self.parent.parent.frame()) - return - if functype == 'classmethod': - yield self.parent.parent.frame() - return - if name == self.vararg: - yield const_factory(()) - return - if name == self.kwarg: - yield const_factory({}) - return - # if there is a default value, yield it. And then yield YES to reflect - # we can't guess given argument value - try: - context = copy_context(context) - for infered in self.default_value(name).infer(context): - yield infered - yield YES - except NoDefault: - yield YES - - -def arguments_assigned_stmts(self, node, context, asspath=None): - if context.callcontext: - # reset call context/name - callcontext = context.callcontext - context = copy_context(context) - context.callcontext = None - for infered in callcontext.infer_argument(self.parent, node.name, context): - yield infered - return - for infered in _arguments_infer_argname(self, node.name, context): - yield infered -nodes.Arguments.assigned_stmts = arguments_assigned_stmts - - -def assign_assigned_stmts(self, node, context=None, asspath=None): - if not asspath: - yield self.value - return - for infered in _resolve_asspart(self.value.infer(context), asspath, context): - yield infered -nodes.Assign.assigned_stmts = raise_if_nothing_infered(assign_assigned_stmts) -nodes.AugAssign.assigned_stmts = raise_if_nothing_infered(assign_assigned_stmts) - - -def _resolve_asspart(parts, asspath, context): - """recursive function to resolve multiple assignments""" - asspath = asspath[:] - index = asspath.pop(0) - for part in parts: - if hasattr(part, 'getitem'): - try: - assigned = part.getitem(index, context) - # XXX raise a specific exception to avoid potential hiding of - # unexpected exception ? - except (TypeError, IndexError): - return - if not asspath: - # we achieved to resolved the assignment path, don't infer the - # last part - yield assigned - elif assigned is YES: - return - else: - # we are not yet on the last part of the path search on each - # possibly inferred value - try: - for infered in _resolve_asspart(assigned.infer(context), - asspath, context): - yield infered - except InferenceError: - return - - -def excepthandler_assigned_stmts(self, node, context=None, asspath=None): - for assigned in unpack_infer(self.type): - if isinstance(assigned, nodes.Class): - assigned = Instance(assigned) - yield assigned -nodes.ExceptHandler.assigned_stmts = raise_if_nothing_infered(excepthandler_assigned_stmts) - - -def with_assigned_stmts(self, node, context=None, asspath=None): - if asspath is None: - for _, vars in self.items: - for lst in vars.infer(context): - if isinstance(lst, (nodes.Tuple, nodes.List)): - for item in lst.nodes: - yield item -nodes.With.assigned_stmts = raise_if_nothing_infered(with_assigned_stmts) - - diff -Nru astroid-1.0.1/raw_building.py astroid-1.3.8/raw_building.py --- astroid-1.0.1/raw_building.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/raw_building.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,351 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""this module contains a set of functions to create astroid trees from scratch -(build_* functions) or from living object (object_build_* functions) -""" - -__docformat__ = "restructuredtext en" - -import sys -from os.path import abspath -from inspect import (getargspec, isdatadescriptor, isfunction, ismethod, - ismethoddescriptor, isclass, isbuiltin) - -from astroid.node_classes import CONST_CLS -from astroid.nodes import (Module, Class, Const, const_factory, From, - Function, EmptyNode, Name, Arguments) -from astroid.bases import BUILTINS, Generator -from astroid.manager import AstroidManager -MANAGER = AstroidManager() - -_CONSTANTS = tuple(CONST_CLS) # the keys of CONST_CLS eg python builtin types - -def _attach_local_node(parent, node, name): - node.name = name # needed by add_local_node - parent.add_local_node(node) - -_marker = object() - -def attach_dummy_node(node, name, object=_marker): - """create a dummy node and register it in the locals of the given - node with the specified name - """ - enode = EmptyNode() - enode.object = object - _attach_local_node(node, enode, name) - -EmptyNode.has_underlying_object = lambda self: self.object is not _marker - -def attach_const_node(node, name, value): - """create a Const node and register it in the locals of the given - node with the specified name - """ - if not name in node.special_attributes: - _attach_local_node(node, const_factory(value), name) - -def attach_import_node(node, modname, membername): - """create a From node and register it in the locals of the given - node with the specified name - """ - from_node = From(modname, [(membername, None)]) - _attach_local_node(node, from_node, membername) - - -def build_module(name, doc=None): - """create and initialize a astroid Module node""" - node = Module(name, doc, pure_python=False) - node.package = False - node.parent = None - return node - -def build_class(name, basenames=(), doc=None): - """create and initialize a astroid Class node""" - node = Class(name, doc) - for base in basenames: - basenode = Name() - basenode.name = base - node.bases.append(basenode) - basenode.parent = node - return node - -def build_function(name, args=None, defaults=None, flag=0, doc=None): - """create and initialize a astroid Function node""" - args, defaults = args or [], defaults or [] - # first argument is now a list of decorators - func = Function(name, doc) - func.args = argsnode = Arguments() - argsnode.args = [] - for arg in args: - argsnode.args.append(Name()) - argsnode.args[-1].name = arg - argsnode.args[-1].parent = argsnode - argsnode.defaults = [] - for default in defaults: - argsnode.defaults.append(const_factory(default)) - argsnode.defaults[-1].parent = argsnode - argsnode.kwarg = None - argsnode.vararg = None - argsnode.parent = func - if args: - register_arguments(func) - return func - - -def build_from_import(fromname, names): - """create and initialize an astroid From import statement""" - return From(fromname, [(name, None) for name in names]) - -def register_arguments(func, args=None): - """add given arguments to local - - args is a list that may contains nested lists - (i.e. def func(a, (b, c, d)): ...) - """ - if args is None: - args = func.args.args - if func.args.vararg: - func.set_local(func.args.vararg, func.args) - if func.args.kwarg: - func.set_local(func.args.kwarg, func.args) - for arg in args: - if isinstance(arg, Name): - func.set_local(arg.name, arg) - else: - register_arguments(func, arg.elts) - -def object_build_class(node, member, localname): - """create astroid for a living class object""" - basenames = [base.__name__ for base in member.__bases__] - return _base_class_object_build(node, member, basenames, - localname=localname) - -def object_build_function(node, member, localname): - """create astroid for a living function object""" - args, varargs, varkw, defaults = getargspec(member) - if varargs is not None: - args.append(varargs) - if varkw is not None: - args.append(varkw) - func = build_function(getattr(member, '__name__', None) or localname, args, - defaults, member.func_code.co_flags, member.__doc__) - node.add_local_node(func, localname) - -def object_build_datadescriptor(node, member, name): - """create astroid for a living data descriptor object""" - return _base_class_object_build(node, member, [], name) - -def object_build_methoddescriptor(node, member, localname): - """create astroid for a living method descriptor object""" - # FIXME get arguments ? - func = build_function(getattr(member, '__name__', None) or localname, - doc=member.__doc__) - # set node's arguments to None to notice that we have no information, not - # and empty argument list - func.args.args = None - node.add_local_node(func, localname) - -def _base_class_object_build(node, member, basenames, name=None, localname=None): - """create astroid for a living class object, with a given set of base names - (e.g. ancestors) - """ - klass = build_class(name or getattr(member, '__name__', None) or localname, - basenames, member.__doc__) - klass._newstyle = isinstance(member, type) - node.add_local_node(klass, localname) - try: - # limit the instantiation trick since it's too dangerous - # (such as infinite test execution...) - # this at least resolves common case such as Exception.args, - # OSError.errno - if issubclass(member, Exception): - instdict = member().__dict__ - else: - raise TypeError - except: - pass - else: - for name, obj in instdict.items(): - valnode = EmptyNode() - valnode.object = obj - valnode.parent = klass - valnode.lineno = 1 - klass.instance_attrs[name] = [valnode] - return klass - - - - -class InspectBuilder(object): - """class for building nodes from living object - - this is actually a really minimal representation, including only Module, - Function and Class nodes and some others as guessed. - """ - - # astroid from living objects ############################################### - - def __init__(self): - self._done = {} - self._module = None - - def inspect_build(self, module, modname=None, path=None): - """build astroid from a living module (i.e. using inspect) - this is used when there is no python source code available (either - because it's a built-in module or because the .py is not available) - """ - self._module = module - if modname is None: - modname = module.__name__ - try: - node = build_module(modname, module.__doc__) - except AttributeError: - # in jython, java modules have no __doc__ (see #109562) - node = build_module(modname) - node.file = node.path = path and abspath(path) or path - MANAGER.astroid_cache[modname] = node - node.package = hasattr(module, '__path__') - self._done = {} - self.object_build(node, module) - return node - - def object_build(self, node, obj): - """recursive method which create a partial ast from real objects - (only function, class, and method are handled) - """ - if obj in self._done: - return self._done[obj] - self._done[obj] = node - for name in dir(obj): - try: - member = getattr(obj, name) - except AttributeError: - # damned ExtensionClass.Base, I know you're there ! - attach_dummy_node(node, name) - continue - if ismethod(member): - member = member.im_func - if isfunction(member): - # verify this is not an imported function - filename = getattr(member.func_code, 'co_filename', None) - if filename is None: - assert isinstance(member, object) - object_build_methoddescriptor(node, member, name) - elif filename != getattr(self._module, '__file__', None): - attach_dummy_node(node, name, member) - else: - object_build_function(node, member, name) - elif isbuiltin(member): - if self.imported_member(node, member, name): - #if obj is object: - # print 'skippp', obj, name, member - continue - object_build_methoddescriptor(node, member, name) - elif isclass(member): - if self.imported_member(node, member, name): - continue - if member in self._done: - class_node = self._done[member] - if not class_node in node.locals.get(name, ()): - node.add_local_node(class_node, name) - else: - class_node = object_build_class(node, member, name) - # recursion - self.object_build(class_node, member) - if name == '__class__' and class_node.parent is None: - class_node.parent = self._done[self._module] - elif ismethoddescriptor(member): - assert isinstance(member, object) - object_build_methoddescriptor(node, member, name) - elif isdatadescriptor(member): - assert isinstance(member, object) - object_build_datadescriptor(node, member, name) - elif type(member) in _CONSTANTS: - attach_const_node(node, name, member) - else: - # create an empty node so that the name is actually defined - attach_dummy_node(node, name, member) - - def imported_member(self, node, member, name): - """verify this is not an imported class or handle it""" - # /!\ some classes like ExtensionClass doesn't have a __module__ - # attribute ! Also, this may trigger an exception on badly built module - # (see http://www.logilab.org/ticket/57299 for instance) - try: - modname = getattr(member, '__module__', None) - except: - # XXX use logging - print 'unexpected error while building astroid from living object' - import traceback - traceback.print_exc() - modname = None - if modname is None: - if name in ('__new__', '__subclasshook__'): - # Python 2.5.1 (r251:54863, Sep 1 2010, 22:03:14) - # >>> print object.__new__.__module__ - # None - modname = BUILTINS - else: - attach_dummy_node(node, name, member) - return True - if {'gtk': 'gtk._gtk'}.get(modname, modname) != self._module.__name__: - # check if it sounds valid and then add an import node, else use a - # dummy node - try: - getattr(sys.modules[modname], name) - except (KeyError, AttributeError): - attach_dummy_node(node, name, member) - else: - attach_import_node(node, modname, name) - return True - return False - - -### astroid boot strapping ################################################### ### -Astroid_BUILDER = InspectBuilder() - -_CONST_PROXY = {} -def astroid_boot_strapping(): - """astroid boot strapping the builtins module""" - # this boot strapping is necessary since we need the Const nodes to - # inspect_build builtins, and then we can proxy Const - from logilab.common.compat import builtins - astroid_builtin = Astroid_BUILDER.inspect_build(builtins) - for cls, node_cls in CONST_CLS.items(): - if cls is type(None): - proxy = build_class('NoneType') - proxy.parent = astroid_builtin - else: - proxy = astroid_builtin.getattr(cls.__name__)[0] - if cls in (dict, list, set, tuple): - node_cls._proxied = proxy - else: - _CONST_PROXY[cls] = proxy - -astroid_boot_strapping() - -# TODO : find a nicer way to handle this situation; -# However __proxied introduced an -# infinite recursion (see https://bugs.launchpad.net/pylint/+bug/456870) -def _set_proxied(const): - return _CONST_PROXY[const.value.__class__] -Const._proxied = property(_set_proxied) - -from types import GeneratorType -Generator._proxied = Class(GeneratorType.__name__, GeneratorType.__doc__) -Astroid_BUILDER.object_build(Generator._proxied, GeneratorType) - diff -Nru astroid-1.0.1/README astroid-1.3.8/README --- astroid-1.0.1/README 2013-07-29 15:04:24.000000000 +0000 +++ astroid-1.3.8/README 2015-08-02 19:35:46.000000000 +0000 @@ -1,3 +1,7 @@ +.. image:: https://drone.io/bitbucket.org/logilab/astroid/status.png + :alt: drone.io Build Status + :target: https://drone.io/bitbucket.org/logilab/astroid + Astroid ======= @@ -45,12 +49,17 @@ information and archives. You may find older archives at http://lists.logilab.org/mailman/listinfo/python-projects . +Python Versions +--------------- + +astroid is compatible with Python 2.7 as well as 3.3 and later. astroid uses +the same code base for both Python versions, using six. + Test ---- Tests are in the 'test' subdirectory. To launch the whole tests suite at once, you may use the 'pytest' utility from logilab-common (simply -type 'pytest' from within this directory) or if you're running python ->= 2.7, using discover, for instance:: +type 'pytest' from within this directory) or using unittest discover:: python -m unittest discover -p "unittest*.py" diff -Nru astroid-1.0.1/README.Python3 astroid-1.3.8/README.Python3 --- astroid-1.0.1/README.Python3 2013-07-29 15:04:24.000000000 +0000 +++ astroid-1.3.8/README.Python3 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -Python3 -======= - -Approach --------- - -We maintain a Python 2 base and use 2to3 to generate Python 3 code. - -2to3 is integrated into the distutils installation process and will be run as a -build step when invoked by the python3 interpreter:: - - python3 setup.py install --no-compile - - -Debian ------- - -For the Debian packaging, you can use the debian.py3k/ content against -the debian/ folder:: - - cp debian.py3k/* debian/ - - -Resources ---------- -http://wiki.python.org/moin/PortingPythonToPy3k diff -Nru astroid-1.0.1/rebuilder.py astroid-1.3.8/rebuilder.py --- astroid-1.0.1/rebuilder.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/rebuilder.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,940 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""this module contains utilities for rebuilding a _ast tree in -order to get a single Astroid representation -""" - -import sys -from warnings import warn -from _ast import (Expr as Discard, Str, - # binary operators - Add, Div, FloorDiv, Mod, Mult, Pow, Sub, BitAnd, BitOr, BitXor, - LShift, RShift, - # logical operators - And, Or, - # unary operators - UAdd, USub, Not, Invert, - # comparison operators - Eq, Gt, GtE, In, Is, IsNot, Lt, LtE, NotEq, NotIn, - ) - -from astroid import nodes as new - - -_BIN_OP_CLASSES = {Add: '+', - BitAnd: '&', - BitOr: '|', - BitXor: '^', - Div: '/', - FloorDiv: '//', - Mod: '%', - Mult: '*', - Pow: '**', - Sub: '-', - LShift: '<<', - RShift: '>>'} - -_BOOL_OP_CLASSES = {And: 'and', - Or: 'or'} - -_UNARY_OP_CLASSES = {UAdd: '+', - USub: '-', - Not: 'not', - Invert: '~'} - -_CMP_OP_CLASSES = {Eq: '==', - Gt: '>', - GtE: '>=', - In: 'in', - Is: 'is', - IsNot: 'is not', - Lt: '<', - LtE: '<=', - NotEq: '!=', - NotIn: 'not in'} - -CONST_NAME_TRANSFORMS = {'None': None, - 'True': True, - 'False': False} - -REDIRECT = {'arguments': 'Arguments', - 'Attribute': 'Getattr', - 'comprehension': 'Comprehension', - 'Call': 'CallFunc', - 'ClassDef': 'Class', - "ListCompFor": 'Comprehension', - "GenExprFor": 'Comprehension', - 'excepthandler': 'ExceptHandler', - 'Expr': 'Discard', - 'FunctionDef': 'Function', - 'GeneratorExp': 'GenExpr', - 'ImportFrom': 'From', - 'keyword': 'Keyword', - 'Repr': 'Backquote', - } - -def _init_set_doc(node, newnode): - newnode.doc = None - try: - if isinstance(node.body[0], Discard) and isinstance(node.body[0].value, Str): - newnode.tolineno = node.body[0].lineno - newnode.doc = node.body[0].value.s - node.body = node.body[1:] - - except IndexError: - pass # ast built from scratch - -def _lineno_parent(oldnode, newnode, parent): - newnode.parent = parent - if hasattr(oldnode, 'lineno'): - newnode.lineno = oldnode.lineno - if hasattr(oldnode, 'col_offset'): - newnode.col_offset = oldnode.col_offset - -def _set_infos(oldnode, newnode, parent): - newnode.parent = parent - if hasattr(oldnode, 'lineno'): - newnode.lineno = oldnode.lineno - if hasattr(oldnode, 'col_offset'): - newnode.col_offset = oldnode.col_offset - newnode.set_line_info(newnode.last_child()) # set_line_info accepts None - - - - -class TreeRebuilder(object): - """Rebuilds the _ast tree to become an Astroid tree""" - - def __init__(self, manager): - self._manager = manager - self.asscontext = None - self._metaclass = [''] - self._global_names = [] - self._from_nodes = [] - self._delayed_assattr = [] - self._visit_meths = {} - - def _transform(self, node): - try: - transforms = self._manager.transforms[type(node)] - except KeyError: - return node # no transform registered for this class of node - orig_node = node # copy the reference - for transform_func, predicate in transforms: - if predicate is None or predicate(node): - ret = transform_func(node) - # if the transformation function returns something, it's - # expected to be a replacement for the node - if ret is not None: - if node is not orig_node: - # node has already be modified by some previous - # transformation, warn about it - warn('node %s substitued multiple times' % node) - node = ret - return node - - def visit_module(self, node, modname, package): - """visit a Module node by returning a fresh instance of it""" - newnode = new.Module(modname, None) - newnode.package = package - _lineno_parent(node, newnode, parent=None) - _init_set_doc(node, newnode) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.set_line_info(newnode.last_child()) - return self._transform(newnode) - - def visit(self, node, parent): - cls = node.__class__ - if cls in self._visit_meths: - visit_method = self._visit_meths[cls] - else: - cls_name = cls.__name__ - visit_name = 'visit_' + REDIRECT.get(cls_name, cls_name).lower() - visit_method = getattr(self, visit_name) - self._visit_meths[cls] = visit_method - return self._transform(visit_method(node, parent)) - - def _save_assignment(self, node, name=None): - """save assignement situation since node.parent is not available yet""" - if self._global_names and node.name in self._global_names[-1]: - node.root().set_local(node.name, node) - else: - node.parent.set_local(node.name, node) - - - def visit_arguments(self, node, parent): - """visit a Arguments node by returning a fresh instance of it""" - newnode = new.Arguments() - _lineno_parent(node, newnode, parent) - self.asscontext = "Ass" - 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: - if node.vararg: - newnode.parent.set_local(newnode.vararg, newnode) - if node.kwarg: - newnode.parent.set_local(newnode.kwarg, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_assattr(self, node, parent): - """visit a AssAttr node by returning a fresh instance of it""" - assc, self.asscontext = self.asscontext, None - newnode = new.AssAttr() - _lineno_parent(node, newnode, parent) - newnode.expr = self.visit(node.expr, newnode) - self.asscontext = assc - self._delayed_assattr.append(newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_assert(self, node, parent): - """visit a Assert node by returning a fresh instance of it""" - newnode = new.Assert() - _lineno_parent(node, newnode, parent) - newnode.test = self.visit(node.test, newnode) - if node.msg is not None: - newnode.fail = self.visit(node.msg, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_assign(self, node, parent): - """visit a Assign node by returning a fresh instance of it""" - newnode = new.Assign() - _lineno_parent(node, newnode, parent) - self.asscontext = "Ass" - newnode.targets = [self.visit(child, newnode) for child in node.targets] - self.asscontext = None - newnode.value = self.visit(node.value, newnode) - # set some function or metaclass infos XXX explain ? - klass = newnode.parent.frame() - if (isinstance(klass, new.Class) - and isinstance(newnode.value, new.CallFunc) - and isinstance(newnode.value.func, new.Name)): - func_name = newnode.value.func.name - for ass_node in newnode.targets: - try: - meth = klass[ass_node.name] - if isinstance(meth, new.Function): - if func_name in ('classmethod', 'staticmethod'): - meth.type = func_name - elif func_name == 'classproperty': # see lgc.decorators - meth.type = 'classmethod' - meth.extra_decorators.append(newnode.value) - except (AttributeError, KeyError): - continue - elif getattr(newnode.targets[0], 'name', None) == '__metaclass__': - # XXX check more... - self._metaclass[-1] = 'type' # XXX get the actual metaclass - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_assname(self, node, parent, node_name=None): - '''visit a node and return a AssName node''' - newnode = new.AssName() - _set_infos(node, newnode, parent) - newnode.name = node_name - self._save_assignment(newnode) - return newnode - - def visit_augassign(self, node, parent): - """visit a AugAssign node by returning a fresh instance of it""" - newnode = new.AugAssign() - _lineno_parent(node, newnode, parent) - newnode.op = _BIN_OP_CLASSES[node.op.__class__] + "=" - self.asscontext = "Ass" - newnode.target = self.visit(node.target, newnode) - self.asscontext = None - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_backquote(self, node, parent): - """visit a Backquote node by returning a fresh instance of it""" - newnode = new.Backquote() - _lineno_parent(node, newnode, parent) - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_binop(self, node, parent): - """visit a BinOp node by returning a fresh instance of it""" - newnode = new.BinOp() - _lineno_parent(node, newnode, parent) - newnode.left = self.visit(node.left, newnode) - newnode.right = self.visit(node.right, newnode) - newnode.op = _BIN_OP_CLASSES[node.op.__class__] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_boolop(self, node, parent): - """visit a BoolOp node by returning a fresh instance of it""" - newnode = new.BoolOp() - _lineno_parent(node, newnode, parent) - newnode.values = [self.visit(child, newnode) for child in node.values] - newnode.op = _BOOL_OP_CLASSES[node.op.__class__] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_break(self, node, parent): - """visit a Break node by returning a fresh instance of it""" - newnode = new.Break() - _set_infos(node, newnode, parent) - return newnode - - def visit_callfunc(self, node, parent): - """visit a CallFunc node by returning a fresh instance of it""" - newnode = new.CallFunc() - _lineno_parent(node, newnode, parent) - newnode.func = self.visit(node.func, newnode) - newnode.args = [self.visit(child, newnode) for child in node.args] - if node.starargs is not None: - newnode.starargs = self.visit(node.starargs, newnode) - if node.kwargs is not None: - newnode.kwargs = self.visit(node.kwargs, newnode) - newnode.args.extend(self.visit(child, newnode) for child in node.keywords) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_class(self, node, parent): - """visit a Class node to become astroid""" - self._metaclass.append(self._metaclass[-1]) - newnode = new.Class(node.name, None) - _lineno_parent(node, newnode, parent) - _init_set_doc(node, newnode) - newnode.bases = [self.visit(child, newnode) for child in node.bases] - newnode.body = [self.visit(child, newnode) for child in node.body] - if 'decorator_list' in node._fields and node.decorator_list:# py >= 2.6 - newnode.decorators = self.visit_decorators(node, newnode) - newnode.set_line_info(newnode.last_child()) - metaclass = self._metaclass.pop() - if not newnode.bases: - # no base classes, detect new / style old style according to - # current scope - newnode._newstyle = metaclass == 'type' - newnode.parent.frame().set_local(newnode.name, newnode) - return newnode - - def visit_const(self, node, parent): - """visit a Const node by returning a fresh instance of it""" - newnode = new.Const(node.value) - _set_infos(node, newnode, parent) - return newnode - - def visit_continue(self, node, parent): - """visit a Continue node by returning a fresh instance of it""" - newnode = new.Continue() - _set_infos(node, newnode, parent) - return newnode - - def visit_compare(self, node, parent): - """visit a Compare node by returning a fresh instance of it""" - newnode = new.Compare() - _lineno_parent(node, newnode, parent) - newnode.left = self.visit(node.left, newnode) - newnode.ops = [(_CMP_OP_CLASSES[op.__class__], self.visit(expr, newnode)) - for (op, expr) in zip(node.ops, node.comparators)] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_comprehension(self, node, parent): - """visit a Comprehension node by returning a fresh instance of it""" - newnode = new.Comprehension() - _lineno_parent(node, newnode, parent) - self.asscontext = "Ass" - newnode.target = self.visit(node.target, newnode) - self.asscontext = None - newnode.iter = self.visit(node.iter, newnode) - newnode.ifs = [self.visit(child, newnode) for child in node.ifs] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_decorators(self, node, parent): - """visit a Decorators node by returning a fresh instance of it""" - # /!\ node is actually a _ast.Function node while - # parent is a astroid.nodes.Function node - newnode = new.Decorators() - _lineno_parent(node, newnode, parent) - if 'decorators' in node._fields: # py < 2.6, i.e. 2.5 - decorators = node.decorators - else: - decorators= node.decorator_list - newnode.nodes = [self.visit(child, newnode) for child in decorators] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_delete(self, node, parent): - """visit a Delete node by returning a fresh instance of it""" - newnode = new.Delete() - _lineno_parent(node, newnode, parent) - self.asscontext = "Del" - newnode.targets = [self.visit(child, newnode) for child in node.targets] - self.asscontext = None - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_dict(self, node, parent): - """visit a Dict node by returning a fresh instance of it""" - newnode = new.Dict() - _lineno_parent(node, newnode, parent) - newnode.items = [(self.visit(key, newnode), self.visit(value, newnode)) - for key, value in zip(node.keys, node.values)] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_dictcomp(self, node, parent): - """visit a DictComp node by returning a fresh instance of it""" - newnode = new.DictComp() - _lineno_parent(node, newnode, parent) - newnode.key = self.visit(node.key, newnode) - newnode.value = self.visit(node.value, newnode) - newnode.generators = [self.visit(child, newnode) - for child in node.generators] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_discard(self, node, parent): - """visit a Discard node by returning a fresh instance of it""" - newnode = new.Discard() - _lineno_parent(node, newnode, parent) - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_ellipsis(self, node, parent): - """visit an Ellipsis node by returning a fresh instance of it""" - newnode = new.Ellipsis() - _set_infos(node, newnode, parent) - return newnode - - def visit_emptynode(self, node, parent): - """visit an EmptyNode node by returning a fresh instance of it""" - newnode = new.EmptyNode() - _set_infos(node, newnode, parent) - return newnode - - def visit_excepthandler(self, node, parent): - """visit an ExceptHandler node by returning a fresh instance of it""" - newnode = new.ExceptHandler() - _lineno_parent(node, newnode, parent) - if node.type is not None: - newnode.type = self.visit(node.type, newnode) - if node.name is not None: - # /!\ node.name can be a tuple - self.asscontext = "Ass" - newnode.name = self.visit(node.name, newnode) - self.asscontext = None - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_exec(self, node, parent): - """visit an Exec node by returning a fresh instance of it""" - newnode = new.Exec() - _lineno_parent(node, newnode, parent) - newnode.expr = self.visit(node.body, newnode) - if node.globals is not None: - newnode.globals = self.visit(node.globals, newnode) - if node.locals is not None: - newnode.locals = self.visit(node.locals, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_extslice(self, node, parent): - """visit an ExtSlice node by returning a fresh instance of it""" - newnode = new.ExtSlice() - _lineno_parent(node, newnode, parent) - newnode.dims = [self.visit(dim, newnode) for dim in node.dims] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_for(self, node, parent): - """visit a For node by returning a fresh instance of it""" - newnode = new.For() - _lineno_parent(node, newnode, parent) - self.asscontext = "Ass" - newnode.target = self.visit(node.target, newnode) - self.asscontext = None - newnode.iter = self.visit(node.iter, newnode) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.orelse = [self.visit(child, newnode) for child in node.orelse] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_from(self, node, parent): - """visit a From node by returning a fresh instance of it""" - names = [(alias.name, alias.asname) for alias in node.names] - newnode = new.From(node.module or '', names, node.level or None) - _set_infos(node, newnode, parent) - # store From names to add them to locals after building - self._from_nodes.append(newnode) - return newnode - - def visit_function(self, node, parent): - """visit an Function node to become astroid""" - self._global_names.append({}) - newnode = new.Function(node.name, None) - _lineno_parent(node, newnode, parent) - _init_set_doc(node, newnode) - newnode.args = self.visit(node.args, newnode) - newnode.body = [self.visit(child, newnode) for child in node.body] - if 'decorators' in node._fields: # py < 2.6 - attr = 'decorators' - else: - attr = 'decorator_list' - decorators = getattr(node, attr) - if decorators: - newnode.decorators = self.visit_decorators(node, newnode) - newnode.set_line_info(newnode.last_child()) - self._global_names.pop() - frame = newnode.parent.frame() - if isinstance(frame, new.Class): - if newnode.name == '__new__': - newnode.type = 'classmethod' - else: - newnode.type = 'method' - if newnode.decorators is not None: - for decorator_expr in newnode.decorators.nodes: - if isinstance(decorator_expr, new.Name): - if decorator_expr.name in ('classmethod', 'staticmethod'): - newnode.type = decorator_expr.name - elif decorator_expr.name == 'classproperty': - newnode.type = 'classmethod' - frame.set_local(newnode.name, newnode) - return newnode - - def visit_genexpr(self, node, parent): - """visit a GenExpr node by returning a fresh instance of it""" - newnode = new.GenExpr() - _lineno_parent(node, newnode, parent) - newnode.elt = self.visit(node.elt, newnode) - newnode.generators = [self.visit(child, newnode) for child in node.generators] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_getattr(self, node, parent): - """visit a Getattr node by returning a fresh instance of it""" - if self.asscontext == "Del": - # FIXME : maybe we should reintroduce and visit_delattr ? - # for instance, deactivating asscontext - newnode = new.DelAttr() - elif self.asscontext == "Ass": - # FIXME : maybe we should call visit_assattr ? - newnode = new.AssAttr() - self._delayed_assattr.append(newnode) - else: - newnode = new.Getattr() - _lineno_parent(node, newnode, parent) - asscontext, self.asscontext = self.asscontext, None - newnode.expr = self.visit(node.value, newnode) - self.asscontext = asscontext - newnode.attrname = node.attr - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_global(self, node, parent): - """visit an Global node to become astroid""" - newnode = new.Global(node.names) - _set_infos(node, newnode, parent) - if self._global_names: # global at the module level, no effect - for name in node.names: - self._global_names[-1].setdefault(name, []).append(newnode) - return newnode - - def visit_if(self, node, parent): - """visit a If node by returning a fresh instance of it""" - newnode = new.If() - _lineno_parent(node, newnode, parent) - newnode.test = self.visit(node.test, newnode) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.orelse = [self.visit(child, newnode) for child in node.orelse] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_ifexp(self, node, parent): - """visit a IfExp node by returning a fresh instance of it""" - newnode = new.IfExp() - _lineno_parent(node, newnode, parent) - newnode.test = self.visit(node.test, newnode) - newnode.body = self.visit(node.body, newnode) - newnode.orelse = self.visit(node.orelse, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_import(self, node, parent): - """visit a Import node by returning a fresh instance of it""" - newnode = new.Import() - _set_infos(node, newnode, parent) - newnode.names = [(alias.name, alias.asname) for alias in node.names] - # save import names in parent's locals: - for (name, asname) in newnode.names: - name = asname or name - newnode.parent.set_local(name.split('.')[0], newnode) - return newnode - - def visit_index(self, node, parent): - """visit a Index node by returning a fresh instance of it""" - newnode = new.Index() - _lineno_parent(node, newnode, parent) - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_keyword(self, node, parent): - """visit a Keyword node by returning a fresh instance of it""" - newnode = new.Keyword() - _lineno_parent(node, newnode, parent) - newnode.arg = node.arg - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_lambda(self, node, parent): - """visit a Lambda node by returning a fresh instance of it""" - newnode = new.Lambda() - _lineno_parent(node, newnode, parent) - newnode.args = self.visit(node.args, newnode) - newnode.body = self.visit(node.body, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_list(self, node, parent): - """visit a List node by returning a fresh instance of it""" - newnode = new.List() - _lineno_parent(node, newnode, parent) - newnode.elts = [self.visit(child, newnode) for child in node.elts] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_listcomp(self, node, parent): - """visit a ListComp node by returning a fresh instance of it""" - newnode = new.ListComp() - _lineno_parent(node, newnode, parent) - newnode.elt = self.visit(node.elt, newnode) - newnode.generators = [self.visit(child, newnode) - for child in node.generators] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_name(self, node, parent): - """visit a Name node by returning a fresh instance of it""" - # True and False can be assigned to something in py2x, so we have to - # check first the asscontext - if self.asscontext == "Del": - newnode = new.DelName() - elif self.asscontext is not None: # Ass - assert self.asscontext == "Ass" - newnode = new.AssName() - elif node.id in CONST_NAME_TRANSFORMS: - newnode = new.Const(CONST_NAME_TRANSFORMS[node.id]) - _set_infos(node, newnode, parent) - return newnode - else: - newnode = new.Name() - _lineno_parent(node, newnode, parent) - newnode.name = node.id - # XXX REMOVE me : - if self.asscontext in ('Del', 'Ass'): # 'Aug' ?? - self._save_assignment(newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_bytes(self, node, parent): - """visit a Bytes node by returning a fresh instance of Const""" - newnode = new.Const(node.s) - _set_infos(node, newnode, parent) - return newnode - - def visit_num(self, node, parent): - """visit a Num node by returning a fresh instance of Const""" - newnode = new.Const(node.n) - _set_infos(node, newnode, parent) - return newnode - - def visit_pass(self, node, parent): - """visit a Pass node by returning a fresh instance of it""" - newnode = new.Pass() - _set_infos(node, newnode, parent) - return newnode - - def visit_str(self, node, parent): - """visit a Str node by returning a fresh instance of Const""" - newnode = new.Const(node.s) - _set_infos(node, newnode, parent) - return newnode - - def visit_print(self, node, parent): - """visit a Print node by returning a fresh instance of it""" - newnode = new.Print() - _lineno_parent(node, newnode, parent) - newnode.nl = node.nl - if node.dest is not None: - newnode.dest = self.visit(node.dest, newnode) - newnode.values = [self.visit(child, newnode) for child in node.values] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_raise(self, node, parent): - """visit a Raise node by returning a fresh instance of it""" - newnode = new.Raise() - _lineno_parent(node, newnode, parent) - if node.type is not None: - newnode.exc = self.visit(node.type, newnode) - if node.inst is not None: - newnode.inst = self.visit(node.inst, newnode) - if node.tback is not None: - newnode.tback = self.visit(node.tback, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_return(self, node, parent): - """visit a Return node by returning a fresh instance of it""" - newnode = new.Return() - _lineno_parent(node, newnode, parent) - if node.value is not None: - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_set(self, node, parent): - """visit a Set node by returning a fresh instance of it""" - newnode = new.Set() - _lineno_parent(node, newnode, parent) - newnode.elts = [self.visit(child, newnode) for child in node.elts] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_setcomp(self, node, parent): - """visit a SetComp node by returning a fresh instance of it""" - newnode = new.SetComp() - _lineno_parent(node, newnode, parent) - newnode.elt = self.visit(node.elt, newnode) - newnode.generators = [self.visit(child, newnode) - for child in node.generators] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_slice(self, node, parent): - """visit a Slice node by returning a fresh instance of it""" - newnode = new.Slice() - _lineno_parent(node, newnode, parent) - if node.lower is not None: - newnode.lower = self.visit(node.lower, newnode) - if node.upper is not None: - newnode.upper = self.visit(node.upper, newnode) - if node.step is not None: - newnode.step = self.visit(node.step, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_subscript(self, node, parent): - """visit a Subscript node by returning a fresh instance of it""" - newnode = new.Subscript() - _lineno_parent(node, newnode, parent) - subcontext, self.asscontext = self.asscontext, None - newnode.value = self.visit(node.value, newnode) - newnode.slice = self.visit(node.slice, newnode) - self.asscontext = subcontext - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_tryexcept(self, node, parent): - """visit a TryExcept node by returning a fresh instance of it""" - newnode = new.TryExcept() - _lineno_parent(node, newnode, parent) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.handlers = [self.visit(child, newnode) for child in node.handlers] - newnode.orelse = [self.visit(child, newnode) for child in node.orelse] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_tryfinally(self, node, parent): - """visit a TryFinally node by returning a fresh instance of it""" - newnode = new.TryFinally() - _lineno_parent(node, newnode, parent) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.finalbody = [self.visit(n, newnode) for n in node.finalbody] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_tuple(self, node, parent): - """visit a Tuple node by returning a fresh instance of it""" - newnode = new.Tuple() - _lineno_parent(node, newnode, parent) - newnode.elts = [self.visit(child, newnode) for child in node.elts] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_unaryop(self, node, parent): - """visit a UnaryOp node by returning a fresh instance of it""" - newnode = new.UnaryOp() - _lineno_parent(node, newnode, parent) - newnode.operand = self.visit(node.operand, newnode) - newnode.op = _UNARY_OP_CLASSES[node.op.__class__] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_while(self, node, parent): - """visit a While node by returning a fresh instance of it""" - newnode = new.While() - _lineno_parent(node, newnode, parent) - newnode.test = self.visit(node.test, newnode) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.orelse = [self.visit(child, newnode) for child in node.orelse] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_with(self, node, parent): - newnode = new.With() - _lineno_parent(node, newnode, parent) - expr = self.visit(node.context_expr, newnode) - self.asscontext = "Ass" - if node.optional_vars is not None: - vars = self.visit(node.optional_vars, newnode) - else: - vars = None - self.asscontext = None - newnode.items = [(expr, vars)] - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_yield(self, node, parent): - """visit a Yield node by returning a fresh instance of it""" - newnode = new.Yield() - _lineno_parent(node, newnode, parent) - if node.value is not None: - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - -class TreeRebuilder3k(TreeRebuilder): - """extend and overwrite TreeRebuilder for python3k""" - - def visit_arg(self, node, parent): - """visit a arg node by returning a fresh AssName instance""" - # the node is coming from py>=3.0, but we use AssName in py2.x - # 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() - _lineno_parent(node, newnode, parent) - if node.type is not None: - newnode.type = self.visit(node.type, newnode) - if node.name is not None: - newnode.name = self.visit_assname(node, newnode, node.name) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_nonlocal(self, node, parent): - """visit a Nonlocal node and return a new instance of it""" - newnode = new.Nonlocal(node.names) - _set_infos(node, newnode, parent) - return newnode - - def visit_raise(self, node, parent): - """visit a Raise node by returning a fresh instance of it""" - newnode = new.Raise() - _lineno_parent(node, newnode, parent) - # no traceback; anyway it is not used in Pylint - if node.exc is not None: - newnode.exc = self.visit(node.exc, newnode) - if node.cause is not None: - newnode.cause = self.visit(node.cause, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_starred(self, node, parent): - """visit a Starred node and return a new instance of it""" - newnode = new.Starred() - _lineno_parent(node, newnode, parent) - newnode.value = self.visit(node.value, newnode) - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_try(self, node, parent): - # python 3.3 introduce a new Try node replacing TryFinally/TryExcept nodes - if node.finalbody: - newnode = new.TryFinally() - _lineno_parent(node, newnode, parent) - newnode.finalbody = [self.visit(n, newnode) for n in node.finalbody] - if node.handlers: - excnode = new.TryExcept() - _lineno_parent(node, excnode, newnode) - excnode.body = [self.visit(child, excnode) for child in node.body] - excnode.handlers = [self.visit(child, excnode) for child in node.handlers] - excnode.orelse = [self.visit(child, excnode) for child in node.orelse] - excnode.set_line_info(excnode.last_child()) - newnode.body = [excnode] - else: - newnode.body = [self.visit(child, newnode) for child in node.body] - elif node.handlers: - newnode = new.TryExcept() - _lineno_parent(node, newnode, parent) - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.handlers = [self.visit(child, newnode) for child in node.handlers] - newnode.orelse = [self.visit(child, newnode) for child in node.orelse] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_with(self, node, parent): - if 'items' not in node._fields: - # python < 3.3 - return super(TreeRebuilder3k, self).visit_with(node, parent) - - newnode = new.With() - _lineno_parent(node, newnode, parent) - def visit_child(child): - expr = self.visit(child.context_expr, newnode) - self.asscontext = 'Ass' - if child.optional_vars: - var = self.visit(child.optional_vars, newnode) - else: - var = None - self.asscontext = None - return expr, var - newnode.items = [visit_child(child) - for child in node.items] - newnode.body = [self.visit(child, newnode) for child in node.body] - newnode.set_line_info(newnode.last_child()) - return newnode - - def visit_yieldfrom(self, node, parent): - return self.visit_yield(node, parent) - -if sys.version_info >= (3, 0): - TreeRebuilder = TreeRebuilder3k - - diff -Nru astroid-1.0.1/scoped_nodes.py astroid-1.3.8/scoped_nodes.py --- astroid-1.0.1/scoped_nodes.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/scoped_nodes.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,992 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""This module contains the classes for "scoped" node, i.e. which are opening a -new local scope in the language definition : Module, Class, Function (and -Lambda, GenExpr, DictComp and SetComp to some extent). -""" -from __future__ import with_statement - -__doctype__ = "restructuredtext en" - -import sys -from itertools import chain - -from logilab.common.compat import builtins -from logilab.common.decorators import cached - -from astroid.exceptions import NotFoundError, \ - AstroidBuildingException, InferenceError -from astroid.node_classes import Const, DelName, DelAttr, \ - Dict, From, List, Pass, Raise, Return, Tuple, Yield, \ - LookupMixIn, const_factory as cf, unpack_infer -from astroid.bases import NodeNG, InferenceContext, Instance,\ - YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, copy_context, \ - BUILTINS -from astroid.mixins import FilterStmtsMixin -from astroid.bases import Statement -from astroid.manager import AstroidManager - - -def remove_nodes(func, cls): - def wrapper(*args, **kwargs): - nodes = [n for n in func(*args, **kwargs) if not isinstance(n, cls)] - if not nodes: - raise NotFoundError() - return nodes - return wrapper - - -def function_to_method(n, klass): - if isinstance(n, Function): - if n.type == 'classmethod': - return BoundMethod(n, klass) - if n.type != 'staticmethod': - return UnboundMethod(n) - return n - -def std_special_attributes(self, name, add_locals=True): - if add_locals: - locals = self.locals - else: - locals = {} - if name == '__name__': - return [cf(self.name)] + locals.get(name, []) - if name == '__doc__': - return [cf(self.doc)] + locals.get(name, []) - if name == '__dict__': - return [Dict()] + locals.get(name, []) - raise NotFoundError(name) - -MANAGER = AstroidManager() -def builtin_lookup(name): - """lookup a name into the builtin module - return the list of matching statements and the astroid for the builtin - module - """ - builtin_astroid = MANAGER.ast_from_module(builtins) - if name == '__dict__': - return builtin_astroid, () - try: - stmts = builtin_astroid.locals[name] - except KeyError: - stmts = () - return builtin_astroid, stmts - - -# TODO move this Mixin to mixins.py; problem: 'Function' in _scope_lookup -class LocalsDictNodeNG(LookupMixIn, NodeNG): - """ this class provides locals handling common to Module, Function - and Class nodes, including a dict like interface for direct access - to locals information - """ - - # attributes below are set by the builder module or by raw factories - - # dictionary of locals with name as key and node defining the local as - # value - - def qname(self): - """return the 'qualified' name of the node, eg module.name, - module.class.name ... - """ - if self.parent is None: - return self.name - return '%s.%s' % (self.parent.frame().qname(), self.name) - - def frame(self): - """return the first parent frame node (i.e. Module, Function or Class) - """ - return self - - def scope(self): - """return the first node defining a new scope (i.e. Module, - Function, Class, Lambda but also GenExpr, DictComp and SetComp) - """ - return self - - - def _scope_lookup(self, node, name, offset=0): - """XXX method for interfacing the scope lookup""" - try: - stmts = node._filter_stmts(self.locals[name], self, offset) - except KeyError: - stmts = () - if stmts: - return self, stmts - if self.parent: # i.e. not Module - # nested scope: if parent scope is a function, that's fine - # else jump to the module - pscope = self.parent.scope() - if not pscope.is_function: - pscope = pscope.root() - return pscope.scope_lookup(node, name) - return builtin_lookup(name) # Module - - - - def set_local(self, name, stmt): - """define in locals ( is the node defining the name) - if the node is a Module node (i.e. has globals), add the name to - globals - - if the name is already defined, ignore it - """ - #assert not stmt in self.locals.get(name, ()), (self, stmt) - self.locals.setdefault(name, []).append(stmt) - - __setitem__ = set_local - - def _append_node(self, child): - """append a child, linking it in the tree""" - self.body.append(child) - child.parent = self - - def add_local_node(self, child_node, name=None): - """append a child which should alter locals to the given node""" - if name != '__class__': - # add __class__ node as a child will cause infinite recursion later! - self._append_node(child_node) - self.set_local(name or child_node.name, child_node) - - - def __getitem__(self, item): - """method from the `dict` interface returning the first node - associated with the given name in the locals dictionary - - :type item: str - :param item: the name of the locally defined object - :raises KeyError: if the name is not defined - """ - return self.locals[item][0] - - def __iter__(self): - """method from the `dict` interface returning an iterator on - `self.keys()` - """ - return iter(self.keys()) - - def keys(self): - """method from the `dict` interface returning a tuple containing - locally defined names - """ - return self.locals.keys() - - def values(self): - """method from the `dict` interface returning a tuple containing - locally defined nodes which are instance of `Function` or `Class` - """ - return [self[key] for key in self.keys()] - - def items(self): - """method from the `dict` interface returning a list of tuple - containing each locally defined name with its associated node, - which is an instance of `Function` or `Class` - """ - return zip(self.keys(), self.values()) - - - def __contains__(self, name): - return name in self.locals - has_key = __contains__ - -# Module ##################################################################### - -class Module(LocalsDictNodeNG): - _astroid_fields = ('body',) - - fromlineno = 0 - lineno = 0 - - # attributes below are set by the builder module or by raw factories - - # the file from which as been extracted the astroid representation. It may - # be None if the representation has been built from a built-in module - file = None - # encoding of python source file, so we can get unicode out of it (python2 - # only) - file_encoding = None - # the module name - name = None - # boolean for astroid built from source (i.e. ast) - pure_python = None - # boolean for package module - package = None - # dictionary of globals with name as key and node defining the global - # as value - globals = None - - # names of python special attributes (handled by getattr impl.) - special_attributes = set(('__name__', '__doc__', '__file__', '__path__', - '__dict__')) - # names of module attributes available through the global scope - scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) - - def __init__(self, name, doc, pure_python=True): - self.name = name - self.doc = doc - self.pure_python = pure_python - self.locals = self.globals = {} - self.body = [] - - @property - def file_stream(self): - if self.file is not None: - return open(self.file, 'rb') - return None - - def block_range(self, lineno): - """return block line numbers. - - start from the beginning whatever the given lineno - """ - return self.fromlineno, self.tolineno - - def scope_lookup(self, node, name, offset=0): - if name in self.scope_attrs and not name in self.locals: - try: - return self, self.getattr(name) - except NotFoundError: - return self, () - return self._scope_lookup(node, name, offset) - - def pytype(self): - return '%s.module' % BUILTINS - - def display_type(self): - return 'Module' - - def getattr(self, name, context=None, ignore_locals=False): - if name in self.special_attributes: - if name == '__file__': - return [cf(self.file)] + self.locals.get(name, []) - if name == '__path__' and self.package: - return [List()] + self.locals.get(name, []) - return std_special_attributes(self, name) - if not ignore_locals and name in self.locals: - return self.locals[name] - if self.package: - try: - return [self.import_module(name, relative_only=True)] - except AstroidBuildingException: - raise NotFoundError(name) - except Exception:# XXX pylint tests never pass here; do we need it? - import traceback - traceback.print_exc() - raise NotFoundError(name) - getattr = remove_nodes(getattr, DelName) - - def igetattr(self, name, context=None): - """inferred getattr""" - # set lookup name since this is necessary to infer on import nodes for - # instance - context = copy_context(context) - context.lookupname = name - try: - return _infer_stmts(self.getattr(name, context), context, frame=self) - except NotFoundError: - raise InferenceError(name) - - def fully_defined(self): - """return True if this module has been built from a .py file - and so contains a complete representation including the code - """ - return self.file is not None and self.file.endswith('.py') - - def statement(self): - """return the first parent node marked as statement node - consider a module as a statement... - """ - return self - - def previous_sibling(self): - """module has no sibling""" - return - - def next_sibling(self): - """module has no sibling""" - return - - if sys.version_info < (2, 8): - def absolute_import_activated(self): - for stmt in self.locals.get('absolute_import', ()): - if isinstance(stmt, From) and stmt.modname == '__future__': - return True - return False - else: - absolute_import_activated = lambda self: True - - def import_module(self, modname, relative_only=False, level=None): - """import the given module considering self as context""" - if relative_only and level is None: - level = 0 - absmodname = self.relative_to_absolute_name(modname, level) - try: - return MANAGER.ast_from_module_name(absmodname) - except AstroidBuildingException: - # we only want to import a sub module or package of this module, - # skip here - if relative_only: - raise - return MANAGER.ast_from_module_name(modname) - - def relative_to_absolute_name(self, modname, level): - """return the absolute module name for a relative import. - - The relative import can be implicit or explicit. - """ - # XXX this returns non sens when called on an absolute import - # like 'pylint.checkers.astroid.utils' - # XXX doesn't return absolute name if self.name isn't absolute name - if self.absolute_import_activated() and level is None: - return modname - if level: - if self.package: - level = level - 1 - package_name = self.name.rsplit('.', level)[0] - elif self.package: - package_name = self.name - else: - package_name = self.name.rsplit('.', 1)[0] - if package_name: - if not modname: - return package_name - return '%s.%s' % (package_name, modname) - return modname - - - def wildcard_import_names(self): - """return the list of imported names when this module is 'wildcard - imported' - - It doesn't include the '__builtins__' name which is added by the - current CPython implementation of wildcard imports. - """ - # take advantage of a living module if it exists - try: - living = sys.modules[self.name] - except KeyError: - pass - else: - try: - return living.__all__ - except AttributeError: - return [name for name in living.__dict__.keys() - if not name.startswith('_')] - # else lookup the astroid - # - # We separate the different steps of lookup in try/excepts - # to avoid catching too many Exceptions - # However, we can not analyse dynamically constructed __all__ - try: - all = self['__all__'] - except KeyError: - return [name for name in self.keys() if not name.startswith('_')] - try: - explicit = all.assigned_stmts().next() - except InferenceError: - return [name for name in self.keys() if not name.startswith('_')] - except AttributeError: - # not an assignment node - # XXX infer? - return [name for name in self.keys() if not name.startswith('_')] - try: - # should be a Tuple/List of constant string / 1 string not allowed - return [const.value for const in explicit.elts] - except AttributeError: - return [name for name in self.keys() if not name.startswith('_')] - - -class ComprehensionScope(LocalsDictNodeNG): - def frame(self): - return self.parent.frame() - - scope_lookup = LocalsDictNodeNG._scope_lookup - - -class GenExpr(ComprehensionScope): - _astroid_fields = ('elt', 'generators') - - def __init__(self): - self.locals = {} - self.elt = None - self.generators = [] - - -class DictComp(ComprehensionScope): - _astroid_fields = ('key', 'value', 'generators') - - def __init__(self): - self.locals = {} - self.key = None - self.value = None - self.generators = [] - - -class SetComp(ComprehensionScope): - _astroid_fields = ('elt', 'generators') - - def __init__(self): - self.locals = {} - self.elt = None - self.generators = [] - - -class _ListComp(NodeNG): - """class representing a ListComp node""" - _astroid_fields = ('elt', 'generators') - elt = None - generators = None - -if sys.version_info >= (3, 0): - class ListComp(_ListComp, ComprehensionScope): - """class representing a ListComp node""" - def __init__(self): - self.locals = {} -else: - class ListComp(_ListComp): - """class representing a ListComp node""" - -# Function ################################################################### - - -class Lambda(LocalsDictNodeNG, FilterStmtsMixin): - _astroid_fields = ('args', 'body',) - name = '' - - # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod' - type = 'function' - - def __init__(self): - self.locals = {} - self.args = [] - self.body = [] - - def pytype(self): - if 'method' in self.type: - return '%s.instancemethod' % BUILTINS - return '%s.function' % BUILTINS - - def display_type(self): - if 'method' in self.type: - return 'Method' - return 'Function' - - def callable(self): - return True - - 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) - else: - names = [] - if self.args.vararg: - names.append(self.args.vararg) - if self.args.kwarg: - names.append(self.args.kwarg) - return names - - def infer_call_result(self, caller, context=None): - """infer what a function is returning when called""" - return self.body.infer(context) - - def scope_lookup(self, node, name, offset=0): - 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 - offset = -1 - else: - # check this is not used in function decorators - frame = self - return frame._scope_lookup(node, name, offset) - - -class Function(Statement, Lambda): - _astroid_fields = ('decorators', 'args', 'body') - - special_attributes = set(('__name__', '__doc__', '__dict__')) - is_function = True - # attributes below are set by the builder module or by raw factories - blockstart_tolineno = None - decorators = None - - def __init__(self, name, doc): - self.locals = {} - self.args = [] - self.body = [] - self.decorators = None - self.name = name - self.doc = doc - self.extra_decorators = [] - self.instance_attrs = {} - - def set_line_info(self, lastchild): - self.fromlineno = self.lineno - # lineno is the line number of the first decorator, we want the def statement lineno - if self.decorators is not None: - self.fromlineno += sum(node.tolineno - node.lineno + 1 - for node in self.decorators.nodes) - if self.args.fromlineno < self.fromlineno: - self.args.fromlineno = self.fromlineno - self.tolineno = lastchild.tolineno - self.blockstart_tolineno = self.args.tolineno - - def block_range(self, lineno): - """return block line numbers. - - start from the "def" position whatever the given lineno - """ - return self.fromlineno, self.tolineno - - def getattr(self, name, context=None): - """this method doesn't look in the instance_attrs dictionary since it's - done by an Instance proxy at inference time. - """ - if name == '__module__': - return [cf(self.root().qname())] - if name in self.instance_attrs: - return self.instance_attrs[name] - return std_special_attributes(self, name, False) - - def is_method(self): - """return true if the function node should be considered as a method""" - # check we are defined in a Class, because this is usually expected - # (e.g. pylint...) when is_method() return True - return self.type != 'function' and isinstance(self.parent.frame(), Class) - - def decoratornames(self): - """return a list of decorator qualified names""" - result = set() - decoratornodes = [] - if self.decorators is not None: - decoratornodes += self.decorators.nodes - decoratornodes += self.extra_decorators - for decnode in decoratornodes: - for infnode in decnode.infer(): - result.add(infnode.qname()) - return result - decoratornames = cached(decoratornames) - - def is_bound(self): - """return true if the function is bound to an Instance or a class""" - return self.type == 'classmethod' - - def is_abstract(self, pass_is_abstract=True): - """Returns True if the method is abstract. - - A method is considered abstract if - - the only statement is 'raise NotImplementedError', or - - the only statement is 'pass' and pass_is_abstract is True, or - - the method is annotated with abc.astractproperty/abc.abstractmethod - """ - if self.decorators: - for node in self.decorators.nodes: - try: - infered = node.infer().next() - except InferenceError: - continue - if infered and infered.qname() in ('abc.abstractproperty', - 'abc.abstractmethod'): - return True - - for child_node in self.body: - if isinstance(child_node, Raise): - if child_node.raises_not_implemented(): - return True - if pass_is_abstract and isinstance(child_node, Pass): - return True - return False - # empty function is the same as function with a single "pass" statement - if pass_is_abstract: - return True - - def is_generator(self): - """return true if this is a generator function""" - # XXX should be flagged, not computed - try: - return self.nodes_of_class(Yield, skip_klass=(Function, Lambda)).next() - except StopIteration: - return False - - def infer_call_result(self, caller, context=None): - """infer what a function is returning when called""" - if self.is_generator(): - yield Generator() - return - returns = self.nodes_of_class(Return, skip_klass=Function) - for returnnode in returns: - if returnnode.value is None: - yield Const(None) - else: - try: - for infered in returnnode.value.infer(context): - yield infered - except InferenceError: - yield YES - - -def _rec_get_names(args, names=None): - """return a list of all argument names""" - if names is None: - names = [] - for arg in args: - if isinstance(arg, Tuple): - _rec_get_names(arg.elts, names) - else: - names.append(arg.name) - return names - - -# Class ###################################################################### - -def _class_type(klass, ancestors=None): - """return a Class node type to differ metaclass, interface and exception - from 'regular' classes - """ - # XXX we have to store ancestors in case we have a ancestor loop - if klass._type is not None: - return klass._type - if klass.name == 'type': - klass._type = 'metaclass' - elif klass.name.endswith('Interface'): - klass._type = 'interface' - elif klass.name.endswith('Exception'): - klass._type = 'exception' - else: - if ancestors is None: - ancestors = set() - if klass in ancestors: - # XXX we are in loop ancestors, and have found no type - klass._type = 'class' - return 'class' - ancestors.add(klass) - # print >> sys.stderr, '_class_type', repr(klass) - for base in klass.ancestors(recurs=False): - if _class_type(base, ancestors) != 'class': - klass._type = base.type - break - if klass._type is None: - klass._type = 'class' - return klass._type - -def _iface_hdlr(iface_node): - """a handler function used by interfaces to handle suspicious - interface nodes - """ - return True - - -class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin): - - # some of the attributes below are set by the builder module or - # by a raw factories - - # a dictionary of class instances attributes - _astroid_fields = ('decorators', 'bases', 'body') # name - - decorators = None - special_attributes = set(('__name__', '__doc__', '__dict__', '__module__', - '__bases__', '__mro__', '__subclasses__')) - blockstart_tolineno = None - - _type = None - type = property(_class_type, - doc="class'type, possible values are 'class' | " - "'metaclass' | 'interface' | 'exception'") - - def __init__(self, name, doc): - self.instance_attrs = {} - self.locals = {} - self.bases = [] - self.body = [] - self.name = name - self.doc = doc - - def _newstyle_impl(self, context=None): - if context is None: - context = InferenceContext() - if self._newstyle is not None: - return self._newstyle - for base in self.ancestors(recurs=False, context=context): - if base._newstyle_impl(context): - self._newstyle = True - break - if self._newstyle is None: - self._newstyle = False - return self._newstyle - - _newstyle = None - newstyle = property(_newstyle_impl, - doc="boolean indicating if it's a new style class" - "or not") - - def set_line_info(self, lastchild): - self.fromlineno = self.lineno - self.blockstart_tolineno = self.bases and self.bases[-1].tolineno or self.fromlineno - if lastchild is not None: - self.tolineno = lastchild.tolineno - # else this is a class with only a docstring, then tolineno is (should be) already ok - - def block_range(self, lineno): - """return block line numbers. - - start from the "class" position whatever the given lineno - """ - return self.fromlineno, self.tolineno - - def pytype(self): - if self.newstyle: - return '%s.type' % BUILTINS - return '%s.classobj' % BUILTINS - - def display_type(self): - return 'Class' - - def callable(self): - return True - - def infer_call_result(self, caller, context=None): - """infer what a class is returning when called""" - yield Instance(self) - - def scope_lookup(self, node, name, offset=0): - if node in self.bases: - frame = self.parent.frame() - # line offset to avoid that class A(A) resolve the ancestor to - # the defined class - offset = -1 - else: - frame = self - return frame._scope_lookup(node, name, offset) - - # list of parent class as a list of string (i.e. names as they appear - # in the class definition) XXX bw compat - def basenames(self): - return [bnode.as_string() for bnode in self.bases] - basenames = property(basenames) - - def ancestors(self, recurs=True, context=None): - """return an iterator on the node base classes in a prefixed - depth first order - - :param recurs: - boolean indicating if it should recurse or return direct - ancestors only - """ - # FIXME: should be possible to choose the resolution order - # XXX inference make infinite loops possible here (see BaseTransformer - # manipulation in the builder module for instance) - yielded = set([self]) - if context is None: - context = InferenceContext() - for stmt in self.bases: - with context.restore_path(): - try: - for baseobj in stmt.infer(context): - if not isinstance(baseobj, Class): - # duh ? - continue - if baseobj in yielded: - continue # cf xxx above - yielded.add(baseobj) - yield baseobj - if recurs: - for grandpa in baseobj.ancestors(True, context): - if grandpa in yielded: - continue # cf xxx above - yielded.add(grandpa) - yield grandpa - except InferenceError: - # XXX log error ? - continue - - def local_attr_ancestors(self, name, context=None): - """return an iterator on astroid representation of parent classes - which have defined in their locals - """ - for astroid in self.ancestors(context=context): - if name in astroid: - yield astroid - - def instance_attr_ancestors(self, name, context=None): - """return an iterator on astroid representation of parent classes - which have defined in their instance attribute dictionary - """ - for astroid in self.ancestors(context=context): - if name in astroid.instance_attrs: - yield astroid - - def has_base(self, node): - return node in self.bases - - def local_attr(self, name, context=None): - """return the list of assign node associated to name in this class - locals or in its parents - - :raises `NotFoundError`: - if no attribute with this name has been find in this class or - its parent classes - """ - try: - return self.locals[name] - except KeyError: - # get if from the first parent implementing it if any - for class_node in self.local_attr_ancestors(name, context): - return class_node.locals[name] - raise NotFoundError(name) - local_attr = remove_nodes(local_attr, DelAttr) - - def instance_attr(self, name, context=None): - """return the astroid nodes associated to name in this class instance - attributes dictionary and in its parents - - :raises `NotFoundError`: - if no attribute with this name has been find in this class or - its parent classes - """ - values = self.instance_attrs.get(name, []) - # get all values from parents - for class_node in self.instance_attr_ancestors(name, context): - values += class_node.instance_attrs[name] - if not values: - raise NotFoundError(name) - return values - instance_attr = remove_nodes(instance_attr, DelAttr) - - def instanciate_class(self): - """return Instance of Class node, else return self""" - return Instance(self) - - def getattr(self, name, context=None): - """this method doesn't look in the instance_attrs dictionary since it's - done by an Instance proxy at inference time. - - It may return a YES object if the attribute has not been actually - found but a __getattr__ or __getattribute__ method is defined - """ - values = self.locals.get(name, []) - if name in self.special_attributes: - if name == '__module__': - return [cf(self.root().qname())] + values - # FIXME: do we really need the actual list of ancestors? - # returning [Tuple()] + values don't break any test - # this is ticket http://www.logilab.org/ticket/52785 - # XXX need proper meta class handling + MRO implementation - if name == '__bases__' or (name == '__mro__' and self.newstyle): - node = Tuple() - node.items = self.ancestors(recurs=True, context=context) - return [node] + values - return std_special_attributes(self, name) - # don't modify the list in self.locals! - values = list(values) - for classnode in self.ancestors(recurs=True, context=context): - values += classnode.locals.get(name, []) - if not values: - raise NotFoundError(name) - return values - - def igetattr(self, name, context=None): - """inferred getattr, need special treatment in class to handle - descriptors - """ - # set lookup name since this is necessary to infer on import nodes for - # instance - context = copy_context(context) - context.lookupname = name - try: - for infered in _infer_stmts(self.getattr(name, context), context, - frame=self): - # yield YES object instead of descriptors when necessary - if not isinstance(infered, Const) and isinstance(infered, Instance): - try: - infered._proxied.getattr('__get__', context) - except NotFoundError: - yield infered - else: - yield YES - else: - yield function_to_method(infered, self) - except NotFoundError: - if not name.startswith('__') and self.has_dynamic_getattr(context): - # class handle some dynamic attributes, return a YES object - yield YES - else: - raise InferenceError(name) - - def has_dynamic_getattr(self, context=None): - """return True if the class has a custom __getattr__ or - __getattribute__ method - """ - # need to explicitly handle optparse.Values (setattr is not detected) - if self.name == 'Values' and self.root().name == 'optparse': - return True - try: - self.getattr('__getattr__', context) - return True - except NotFoundError: - #if self.newstyle: XXX cause an infinite recursion error - try: - getattribute = self.getattr('__getattribute__', context)[0] - if getattribute.root().name != BUILTINS: - # class has a custom __getattribute__ defined - return True - except NotFoundError: - pass - return False - - def methods(self): - """return an iterator on all methods defined in the class and - its ancestors - """ - done = {} - for astroid in chain(iter((self,)), self.ancestors()): - for meth in astroid.mymethods(): - if meth.name in done: - continue - done[meth.name] = None - yield meth - - def mymethods(self): - """return an iterator on all methods defined in the class""" - for member in self.values(): - if isinstance(member, Function): - yield member - - def interfaces(self, herited=True, handler_func=_iface_hdlr): - """return an iterator on interfaces implemented by the given - class node - """ - # FIXME: what if __implements__ = (MyIFace, MyParent.__implements__)... - try: - implements = Instance(self).getattr('__implements__')[0] - except NotFoundError: - return - if not herited and not implements.frame() is self: - return - found = set() - missing = False - for iface in unpack_infer(implements): - if iface is YES: - missing = True - continue - if not iface in found and handler_func(iface): - found.add(iface) - yield iface - if missing: - raise InferenceError() diff -Nru astroid-1.0.1/setup.cfg astroid-1.3.8/setup.cfg --- astroid-1.0.1/setup.cfg 2013-10-18 15:34:22.000000000 +0000 +++ astroid-1.3.8/setup.cfg 2015-08-02 20:40:06.000000000 +0000 @@ -1,5 +1,8 @@ -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - +[wheel] +universal = 1 + +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + diff -Nru astroid-1.0.1/setup.py astroid-1.3.8/setup.py --- astroid-1.0.1/setup.py 2013-10-18 15:34:05.000000000 +0000 +++ astroid-1.3.8/setup.py 2015-03-09 22:00:27.000000000 +0000 @@ -17,152 +17,28 @@ # # You should have received a copy of the GNU Lesser General Public License along # with astroid. If not, see . -"""Generic Setup script, takes package info from __pkginfo__.py file. -""" -__docformat__ = "restructuredtext en" - +"""Setup script for astroid.""" import os -import sys -import shutil -from os.path import isdir, exists, join - -try: - if os.environ.get('NO_SETUPTOOLS'): - raise ImportError() - from setuptools import setup - from setuptools.command import install_lib - USE_SETUPTOOLS = 1 -except ImportError: - from distutils.core import setup - from distutils.command import install_lib - USE_SETUPTOOLS = 0 - -try: - # python3 - from distutils.command.build_py import build_py_2to3 as build_py -except ImportError: - # python2.x - from distutils.command.build_py import build_py - -sys.modules.pop('__pkginfo__', None) -# import optional features -__pkginfo__ = __import__("__pkginfo__") -# import required features -from __pkginfo__ import modname, version, license, description, \ - web, author, author_email - -distname = getattr(__pkginfo__, 'distname', modname) -scripts = getattr(__pkginfo__, 'scripts', []) -data_files = getattr(__pkginfo__, 'data_files', None) -subpackage_of = getattr(__pkginfo__, 'subpackage_of', None) -include_dirs = getattr(__pkginfo__, 'include_dirs', []) -ext_modules = getattr(__pkginfo__, 'ext_modules', None) -install_requires = getattr(__pkginfo__, 'install_requires', None) -dependency_links = getattr(__pkginfo__, 'dependency_links', []) -classifiers = getattr(__pkginfo__, 'classifiers', []) - -STD_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build') - -IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~') - -if exists('README'): - long_description = open('README').read() -else: - long_description = '' - -def ensure_scripts(linux_scripts): - """Creates the proper script names required for each platform - (taken from 4Suite) - """ - from distutils import util - if util.get_platform()[:3] == 'win': - scripts_ = [script + '.bat' for script in linux_scripts] - else: - scripts_ = linux_scripts - return scripts_ - -def get_packages(directory, prefix): - """return a list of subpackages for the given directory""" - result = [] - for package in os.listdir(directory): - absfile = join(directory, package) - if isdir(absfile): - if exists(join(absfile, '__init__.py')) or \ - package in ('test', 'tests'): - if prefix: - result.append('%s.%s' % (prefix, package)) - else: - result.append(package) - result += get_packages(absfile, result[-1]) - return result - -EMPTY_FILE = '''"""generated file, don't modify or your data will be lost""" -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - pass -''' - -class MyInstallLib(install_lib.install_lib): - """extend install_lib command to handle package __init__.py if necessary - """ - def run(self): - """overridden from install_lib class""" - install_lib.install_lib.run(self) - # create Products.__init__.py if needed - if subpackage_of: - product_init = join(self.install_dir, subpackage_of, '__init__.py') - if not exists(product_init): - self.announce('creating %s' % product_init) - stream = open(product_init, 'w') - stream.write(EMPTY_FILE) - stream.close() - - -class MyBuildPy(build_py): - """extend build_by command to handle include_dirs variable if necessary - """ - def run(self): - """overridden from install_lib class""" - build_py.run(self) - # manually install included directories if any - if include_dirs: - if subpackage_of: - base = join(subpackage_of, modname) - else: - base = modname - basedir = os.path.join(self.build_lib, base) - for directory in include_dirs: - dest = join(basedir, directory) - shutil.rmtree(dest, ignore_errors=True) - shutil.copytree(directory, dest) - if sys.version_info >= (3, 0): - # process manually python file in include_dirs (test data) - from distutils.util import run_2to3 - print('running 2to3 on', dest) - run_2to3([dest]) - -def install(**kwargs): - """setup entry point""" - if USE_SETUPTOOLS: - if '--force-manifest' in sys.argv: - sys.argv.remove('--force-manifest') - # install-layout option was introduced in 2.5.3-1~exp1 - elif sys.version_info < (2, 5, 4) and '--install-layout=deb' in sys.argv: - sys.argv.remove('--install-layout=deb') - if subpackage_of: - package = subpackage_of + '.' + modname - kwargs['package_dir'] = {package : '.'} - packages = [package] + get_packages(os.getcwd(), package) - if USE_SETUPTOOLS: - kwargs['namespace_packages'] = [subpackage_of] - else: - kwargs['package_dir'] = {modname : '.'} - packages = [modname] + get_packages(os.getcwd(), modname) - if USE_SETUPTOOLS and install_requires: - kwargs['install_requires'] = install_requires - kwargs['dependency_links'] = dependency_links - kwargs['packages'] = packages +from setuptools import setup, find_packages +from setuptools.command import install_lib + +pkginfo = 'astroid/__pkginfo__.py' + +with open(pkginfo, 'rb') as fobj: + exec(compile(fobj.read(), pkginfo, 'exec'), locals()) + +with open('README') as fobj: + long_description = fobj.read() + +class AstroidInstallLib(install_lib.install_lib): + def byte_compile(self, files): + test_datadir = os.path.join('astroid', 'tests', 'testdata') + files = [f for f in files if test_datadir not in f] + install_lib.install_lib.byte_compile(self, files) + + + +def install(): return setup(name = distname, version = version, license = license, @@ -172,13 +48,12 @@ author = author, author_email = author_email, url = web, - scripts = ensure_scripts(scripts), - data_files = data_files, - ext_modules = ext_modules, - cmdclass = {'install_lib': MyInstallLib, - 'build_py': MyBuildPy}, - **kwargs + include_package_data = True, + install_requires = install_requires, + packages = find_packages(), + cmdclass={'install_lib': AstroidInstallLib} ) + if __name__ == '__main__' : install() diff -Nru astroid-1.0.1/test/data/absimport.py astroid-1.3.8/test/data/absimport.py --- astroid-1.0.1/test/data/absimport.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/absimport.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -from __future__ import absolute_import -import email -from email import message diff -Nru astroid-1.0.1/test/data/all.py astroid-1.3.8/test/data/all.py --- astroid-1.0.1/test/data/all.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/all.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ - -name = 'a' -_bla = 2 -other = 'o' -class Aaa: pass - -def func(): print 'yo' - -__all__ = 'Aaa', '_bla', 'name' diff -Nru astroid-1.0.1/test/data/appl/__init__.py astroid-1.3.8/test/data/appl/__init__.py --- astroid-1.0.1/test/data/appl/__init__.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/appl/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -""" -Init -""" diff -Nru astroid-1.0.1/test/data/appl/myConnection.py astroid-1.3.8/test/data/appl/myConnection.py --- astroid-1.0.1/test/data/appl/myConnection.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/appl/myConnection.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -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 -Nru astroid-1.0.1/test/data/email.py astroid-1.3.8/test/data/email.py --- astroid-1.0.1/test/data/email.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/email.py 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -"""fake email module to test absolute import doesn't grab this one""" diff -Nru astroid-1.0.1/test/data/format.py astroid-1.3.8/test/data/format.py --- astroid-1.0.1/test/data/format.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/format.py 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru astroid-1.0.1/test/data/__init__.py astroid-1.3.8/test/data/__init__.py --- astroid-1.0.1/test/data/__init__.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -__revision__="$Id: __init__.py,v 1.1 2005-06-13 20:55:20 syt Exp $" diff -Nru astroid-1.0.1/test/data/module2.py astroid-1.3.8/test/data/module2.py --- astroid-1.0.1/test/data/module2.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/module2.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +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) - diff -Nru astroid-1.0.1/test/data/module.py astroid-1.3.8/test/data/module.py --- astroid-1.0.1/test/data/module.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/module.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -"""test module for astroid -""" - -__revision__ = '$Id: module.py,v 1.2 2005-11-02 11:56:54 syt Exp $' -from logilab.common import modutils -from logilab.common.shellutils import Execute as spawn -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: - print '!!!' - - -class YO: - """hehe""" - a = 1 - - def __init__(self): - try: - self.yo = 1 - except ValueError, 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""" - global MY_DICT - try: - MY_DICT = {} - local = None - autre = [a for (a, b) in MY_DICT if b] - if b in autre: - print 'yo', - else: - if a in autre: - print '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 in b - class_method = classmethod(class_method) - - -def four_args(a, b, c, d): - """four arguments (was nested_args)""" - print a, b, c, d - 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) - map(lambda x, y: (y, x), a) -redirect = four_args - Binary files /tmp/tehDuGV_EZ/astroid-1.0.1/test/data/MyPyPa-0.1.0-py2.5.egg and /tmp/WwBlO9ZnuM/astroid-1.3.8/test/data/MyPyPa-0.1.0-py2.5.egg differ Binary files /tmp/tehDuGV_EZ/astroid-1.0.1/test/data/MyPyPa-0.1.0-py2.5.zip and /tmp/WwBlO9ZnuM/astroid-1.3.8/test/data/MyPyPa-0.1.0-py2.5.zip differ diff -Nru astroid-1.0.1/test/data/noendingnewline.py astroid-1.3.8/test/data/noendingnewline.py --- astroid-1.0.1/test/data/noendingnewline.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/noendingnewline.py 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru astroid-1.0.1/test/data/nonregr.py astroid-1.3.8/test/data/nonregr.py --- astroid-1.0.1/test/data/nonregr.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/nonregr.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -from __future__ import generators - -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 -Nru astroid-1.0.1/test/data/notall.py astroid-1.3.8/test/data/notall.py --- astroid-1.0.1/test/data/notall.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/notall.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ - -name = 'a' -_bla = 2 -other = 'o' -class Aaa: pass - -def func(): print 'yo' - diff -Nru astroid-1.0.1/test/data/SSL1/Connection1.py astroid-1.3.8/test/data/SSL1/Connection1.py --- astroid-1.0.1/test/data/SSL1/Connection1.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/SSL1/Connection1.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -"""M2Crypto.SSL.Connection - -Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" - -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 -Nru astroid-1.0.1/test/data/SSL1/__init__.py astroid-1.3.8/test/data/SSL1/__init__.py --- astroid-1.0.1/test/data/SSL1/__init__.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data/SSL1/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -from Connection1 import Connection diff -Nru astroid-1.0.1/test/data2/clientmodule_test.py astroid-1.3.8/test/data2/clientmodule_test.py --- astroid-1.0.1/test/data2/clientmodule_test.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data2/clientmodule_test.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -""" docstring for file clientmodule.py """ -from data2.suppliermodule_test import Interface as IFace, DoNothing - -class Toto: pass - -class Ancestor: - """ Ancestor method """ - __implements__ = (IFace,) - - def __init__(self, value): - local_variable = 0 - self.attr = 'this method shouldn\'t have a docstring' - self.__value = value - - def get_value(self): - """ nice docstring ;-) """ - return self.__value - - def set_value(self, value): - self.__value = value - return 'this method shouldn\'t have a docstring' - -class Specialization(Ancestor): - TYPE = 'final class' - top = 'class' - - def __init__(self, value, _id): - Ancestor.__init__(self, value) - self._id = _id - self.relation = DoNothing() - self.toto = Toto() - diff -Nru astroid-1.0.1/test/data2/suppliermodule_test.py astroid-1.3.8/test/data2/suppliermodule_test.py --- astroid-1.0.1/test/data2/suppliermodule_test.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/data2/suppliermodule_test.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -""" file suppliermodule.py """ - -class NotImplemented(Exception): - pass - -class Interface: - def get_value(self): - raise NotImplemented() - - def set_value(self, value): - raise NotImplemented() - -class DoNothing : pass diff -Nru astroid-1.0.1/test/fulltest.sh astroid-1.3.8/test/fulltest.sh --- astroid-1.0.1/test/fulltest.sh 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/fulltest.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -#!/bin/sh - -if [ $@ ] ; then - PYVERSIONS=$@ -else - PYVERSIONS="2.3 2.4 2.5 2.6" -fi -PYTEST=`which pytest` -for ver in $PYVERSIONS; do - echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" - echo `python$ver -V` - echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" - python$ver $PYTEST - echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" - echo `python$ver -V` -OO - python$ver -OO $PYTEST -done diff -Nru astroid-1.0.1/test/regrtest_data/absimp/__init__.py astroid-1.3.8/test/regrtest_data/absimp/__init__.py --- astroid-1.0.1/test/regrtest_data/absimp/__init__.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/absimp/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -"""a package with absolute import activated -""" - -from __future__ import absolute_import - diff -Nru astroid-1.0.1/test/regrtest_data/absimp/sidepackage/__init__.py astroid-1.3.8/test/regrtest_data/absimp/sidepackage/__init__.py --- astroid-1.0.1/test/regrtest_data/absimp/sidepackage/__init__.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/absimp/sidepackage/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -"""a side package with nothing in it -""" - diff -Nru astroid-1.0.1/test/regrtest_data/absimp/string.py astroid-1.3.8/test/regrtest_data/absimp/string.py --- astroid-1.0.1/test/regrtest_data/absimp/string.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/absimp/string.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -from __future__ import absolute_import -import string -print string diff -Nru astroid-1.0.1/test/regrtest_data/descriptor_crash.py astroid-1.3.8/test/regrtest_data/descriptor_crash.py --- astroid-1.0.1/test/regrtest_data/descriptor_crash.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/descriptor_crash.py 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru astroid-1.0.1/test/regrtest_data/package/absimport.py astroid-1.3.8/test/regrtest_data/package/absimport.py --- astroid-1.0.1/test/regrtest_data/package/absimport.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/package/absimport.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -from __future__ import absolute_import -import import_package_subpackage_module # fail -print import_package_subpackage_module - -from . import hello as hola - diff -Nru astroid-1.0.1/test/regrtest_data/package/hello.py astroid-1.3.8/test/regrtest_data/package/hello.py --- astroid-1.0.1/test/regrtest_data/package/hello.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/package/hello.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -"""hello module""" - diff -Nru astroid-1.0.1/test/regrtest_data/package/import_package_subpackage_module.py astroid-1.3.8/test/regrtest_data/package/import_package_subpackage_module.py --- astroid-1.0.1/test/regrtest_data/package/import_package_subpackage_module.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/package/import_package_subpackage_module.py 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Nru astroid-1.0.1/test/regrtest_data/package/__init__.py astroid-1.3.8/test/regrtest_data/package/__init__.py --- astroid-1.0.1/test/regrtest_data/package/__init__.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/package/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -"""package's __init__ file""" - - -import subpackage diff -Nru astroid-1.0.1/test/regrtest_data/package/subpackage/__init__.py astroid-1.3.8/test/regrtest_data/package/subpackage/__init__.py --- astroid-1.0.1/test/regrtest_data/package/subpackage/__init__.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/package/subpackage/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -"""package.subpackage""" diff -Nru astroid-1.0.1/test/regrtest_data/package/subpackage/module.py astroid-1.3.8/test/regrtest_data/package/subpackage/module.py --- astroid-1.0.1/test/regrtest_data/package/subpackage/module.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/regrtest_data/package/subpackage/module.py 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -"""package.subpackage.module""" diff -Nru astroid-1.0.1/test/unittest_brain.py astroid-1.3.8/test/unittest_brain.py --- astroid-1.0.1/test/unittest_brain.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_brain.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -# Copyright 2013 Google Inc. All Rights Reserved. -# -# This file is part of astroid. -# -# logilab-astng is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# logilab-astng is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with logilab-astng. If not, see . -"""Tests for basic functionality in astroid.brain.""" - -from astroid import MANAGER -from logilab.common.testlib import TestCase, unittest_main - - -class HashlibTC(TestCase): - def test_hashlib(self): - """Tests that brain extensions for hashlib work.""" - hashlib_module = MANAGER.ast_from_module_name('hashlib') - for class_name in ['md5', 'sha1']: - class_obj = hashlib_module[class_name] - self.assertIn('update', class_obj) - self.assertIn('digest', class_obj) - self.assertIn('hexdigest', class_obj) - self.assertEqual(len(class_obj['__init__'].args.args), 2) - self.assertEqual(len(class_obj['__init__'].args.defaults), 1) - 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) - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_builder.py astroid-1.3.8/test/unittest_builder.py --- astroid-1.0.1/test/unittest_builder.py 2013-10-18 15:34:05.000000000 +0000 +++ astroid-1.3.8/test/unittest_builder.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,733 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""tests for the astroid builder and rebuilder module""" - -import unittest -import sys -from os.path import join, abspath, dirname - -from logilab.common.testlib import TestCase, unittest_main -from pprint import pprint - -from astroid import builder, nodes, InferenceError, NotFoundError -from astroid.nodes import Module -from astroid.bases import YES, BUILTINS -from astroid.manager import AstroidManager - -MANAGER = AstroidManager() - - -from unittest_inference import get_name_node - -import data -from data import module as test_module - -DATA = join(dirname(abspath(__file__)), 'data') - -class FromToLineNoTC(TestCase): - - astroid = builder.AstroidBuilder().file_build(join(DATA, 'format.py')) - - def test_callfunc_lineno(self): - stmts = self.astroid.body - # on line 4: - # function('aeozrijz\ - # earzer', hop) - discard = stmts[0] - self.assertIsInstance(discard, nodes.Discard) - self.assertEqual(discard.fromlineno, 4) - self.assertEqual(discard.tolineno, 5) - callfunc = discard.value - self.assertIsInstance(callfunc, nodes.CallFunc) - self.assertEqual(callfunc.fromlineno, 4) - self.assertEqual(callfunc.tolineno, 5) - name = callfunc.func - self.assertIsInstance(name, nodes.Name) - self.assertEqual(name.fromlineno, 4) - self.assertEqual(name.tolineno, 4) - strarg = callfunc.args[0] - self.assertIsInstance(strarg, nodes.Const) - if hasattr(sys, 'pypy_version_info'): - lineno = 4 - else: - lineno = 5 # no way for this one in CPython (is 4 actually) - self.assertEqual(strarg.fromlineno, lineno) - self.assertEqual(strarg.tolineno, lineno) - namearg = callfunc.args[1] - self.assertIsInstance(namearg, nodes.Name) - self.assertEqual(namearg.fromlineno, 5) - self.assertEqual(namearg.tolineno, 5) - # on line 10: - # fonction(1, - # 2, - # 3, - # 4) - discard = stmts[2] - self.assertIsInstance(discard, nodes.Discard) - self.assertEqual(discard.fromlineno, 10) - self.assertEqual(discard.tolineno, 13) - callfunc = discard.value - self.assertIsInstance(callfunc, nodes.CallFunc) - self.assertEqual(callfunc.fromlineno, 10) - self.assertEqual(callfunc.tolineno, 13) - name = callfunc.func - self.assertIsInstance(name, nodes.Name) - self.assertEqual(name.fromlineno, 10) - self.assertEqual(name.tolineno, 10) - for i, arg in enumerate(callfunc.args): - self.assertIsInstance(arg, nodes.Const) - self.assertEqual(arg.fromlineno, 10+i) - self.assertEqual(arg.tolineno, 10+i) - - def test_function_lineno(self): - stmts = self.astroid.body - # on line 15: - # def definition(a, - # b, - # c): - # return a + b + c - function = stmts[3] - self.assertIsInstance(function, nodes.Function) - self.assertEqual(function.fromlineno, 15) - self.assertEqual(function.tolineno, 18) - return_ = function.body[0] - self.assertIsInstance(return_, nodes.Return) - self.assertEqual(return_.fromlineno, 18) - self.assertEqual(return_.tolineno, 18) - if sys.version_info < (3, 0): - self.assertEqual(function.blockstart_tolineno, 17) - else: - self.skipTest('FIXME http://bugs.python.org/issue10445 ' - '(no line number on function args)') - - def test_decorated_function_lineno(self): - astroid = builder.AstroidBuilder().string_build(''' -@decorator -def function( - arg): - print (arg) -''', __name__, __file__) - function = astroid['function'] - self.assertEqual(function.fromlineno, 3) # XXX discussable, but that's what is expected by pylint right now - self.assertEqual(function.tolineno, 5) - self.assertEqual(function.decorators.fromlineno, 2) - self.assertEqual(function.decorators.tolineno, 2) - if sys.version_info < (3, 0): - self.assertEqual(function.blockstart_tolineno, 4) - else: - self.skipTest('FIXME http://bugs.python.org/issue10445 ' - '(no line number on function args)') - - - def test_class_lineno(self): - stmts = self.astroid.body - # on line 20: - # class debile(dict, - # object): - # pass - class_ = stmts[4] - self.assertIsInstance(class_, nodes.Class) - self.assertEqual(class_.fromlineno, 20) - self.assertEqual(class_.tolineno, 22) - self.assertEqual(class_.blockstart_tolineno, 21) - pass_ = class_.body[0] - self.assertIsInstance(pass_, nodes.Pass) - self.assertEqual(pass_.fromlineno, 22) - self.assertEqual(pass_.tolineno, 22) - - def test_if_lineno(self): - stmts = self.astroid.body - # on line 20: - # if aaaa: pass - # else: - # aaaa,bbbb = 1,2 - # aaaa,bbbb = bbbb,aaaa - if_ = stmts[5] - self.assertIsInstance(if_, nodes.If) - self.assertEqual(if_.fromlineno, 24) - self.assertEqual(if_.tolineno, 27) - self.assertEqual(if_.blockstart_tolineno, 24) - self.assertEqual(if_.orelse[0].fromlineno, 26) - self.assertEqual(if_.orelse[1].tolineno, 27) - - def test_for_while_lineno(self): - for code in (''' -for a in range(4): - print (a) - break -else: - print ("bouh") -''', ''' -while a: - print (a) - break -else: - print ("bouh") -''', - ): - astroid = builder.AstroidBuilder().string_build(code, __name__, __file__) - stmt = astroid.body[0] - self.assertEqual(stmt.fromlineno, 2) - self.assertEqual(stmt.tolineno, 6) - self.assertEqual(stmt.blockstart_tolineno, 2) - self.assertEqual(stmt.orelse[0].fromlineno, 6) # XXX - self.assertEqual(stmt.orelse[0].tolineno, 6) - - - def test_try_except_lineno(self): - astroid = builder.AstroidBuilder().string_build(''' -try: - print (a) -except: - pass -else: - print ("bouh") -''', __name__, __file__) - try_ = astroid.body[0] - self.assertEqual(try_.fromlineno, 2) - self.assertEqual(try_.tolineno, 7) - self.assertEqual(try_.blockstart_tolineno, 2) - self.assertEqual(try_.orelse[0].fromlineno, 7) # XXX - self.assertEqual(try_.orelse[0].tolineno, 7) - hdlr = try_.handlers[0] - self.assertEqual(hdlr.fromlineno, 4) - self.assertEqual(hdlr.tolineno, 5) - self.assertEqual(hdlr.blockstart_tolineno, 4) - - - def test_try_finally_lineno(self): - astroid = builder.AstroidBuilder().string_build(''' -try: - print (a) -finally: - print ("bouh") -''', __name__, __file__) - try_ = astroid.body[0] - self.assertEqual(try_.fromlineno, 2) - self.assertEqual(try_.tolineno, 5) - self.assertEqual(try_.blockstart_tolineno, 2) - self.assertEqual(try_.finalbody[0].fromlineno, 5) # XXX - self.assertEqual(try_.finalbody[0].tolineno, 5) - - - def test_try_finally_25_lineno(self): - astroid = builder.AstroidBuilder().string_build(''' -try: - print (a) -except: - pass -finally: - print ("bouh") -''', __name__, __file__) - try_ = astroid.body[0] - self.assertEqual(try_.fromlineno, 2) - self.assertEqual(try_.tolineno, 7) - self.assertEqual(try_.blockstart_tolineno, 2) - self.assertEqual(try_.finalbody[0].fromlineno, 7) # XXX - self.assertEqual(try_.finalbody[0].tolineno, 7) - - - def test_with_lineno(self): - astroid = builder.AstroidBuilder().string_build(''' -from __future__ import with_statement -with file("/tmp/pouet") as f: - print (f) -''', __name__, __file__) - with_ = astroid.body[1] - self.assertEqual(with_.fromlineno, 3) - self.assertEqual(with_.tolineno, 4) - self.assertEqual(with_.blockstart_tolineno, 3) - - - -class BuilderTC(TestCase): - - def setUp(self): - self.builder = builder.AstroidBuilder() - - def test_border_cases(self): - """check that a file with no trailing new line is parseable""" - self.builder.file_build(join(DATA, 'noendingnewline.py'), 'data.noendingnewline') - self.assertRaises(builder.AstroidBuildingException, - self.builder.file_build, join(DATA, 'inexistant.py'), 'whatever') - - def test_inspect_build0(self): - """test astroid tree build from a living object""" - builtin_astroid = MANAGER.ast_from_module_name(BUILTINS) - if sys.version_info < (3, 0): - fclass = builtin_astroid['file'] - self.assertIn('name', fclass) - self.assertIn('mode', fclass) - self.assertIn('read', fclass) - self.assertTrue(fclass.newstyle) - self.assertTrue(fclass.pytype(), '%s.type' % BUILTINS) - self.assertIsInstance(fclass['read'], nodes.Function) - # check builtin function has args.args == None - dclass = builtin_astroid['dict'] - self.assertIsNone(dclass['has_key'].args.args) - # just check type and object are there - builtin_astroid.getattr('type') - objectastroid = builtin_astroid.getattr('object')[0] - self.assertIsInstance(objectastroid.getattr('__new__')[0], nodes.Function) - # check open file alias - builtin_astroid.getattr('open') - # check 'help' is there (defined dynamically by site.py) - builtin_astroid.getattr('help') - # check property has __init__ - pclass = builtin_astroid['property'] - self.assertIn('__init__', pclass) - self.assertIsInstance(builtin_astroid['None'], nodes.Const) - self.assertIsInstance(builtin_astroid['True'], nodes.Const) - self.assertIsInstance(builtin_astroid['False'], nodes.Const) - if sys.version_info < (3, 0): - self.assertIsInstance(builtin_astroid['Exception'], nodes.From) - self.assertIsInstance(builtin_astroid['NotImplementedError'], nodes.From) - else: - self.assertIsInstance(builtin_astroid['Exception'], nodes.Class) - self.assertIsInstance(builtin_astroid['NotImplementedError'], nodes.Class) - - def test_inspect_build1(self): - time_astroid = MANAGER.ast_from_module_name('time') - self.assertTrue(time_astroid) - self.assertEqual(time_astroid['time'].args.defaults, []) - - def test_inspect_build2(self): - """test astroid tree build from a living object""" - try: - from mx import DateTime - except ImportError: - self.skipTest('test skipped: mxDateTime is not available') - else: - dt_astroid = self.builder.inspect_build(DateTime) - dt_astroid.getattr('DateTime') - # this one is failing since DateTimeType.__module__ = 'builtins' ! - #dt_astroid.getattr('DateTimeType') - - def test_inspect_build3(self): - self.builder.inspect_build(unittest) - - def test_inspect_build_instance(self): - """test astroid tree build from a living object""" - if sys.version_info >= (3, 0): - self.skipTest('The module "exceptions" is gone in py3.x') - import exceptions - builtin_astroid = self.builder.inspect_build(exceptions) - fclass = builtin_astroid['OSError'] - # things like OSError.strerror are now (2.5) data descriptors on the - # class instead of entries in the __dict__ of an instance - container = fclass - self.assertIn('errno', container) - self.assertIn('strerror', container) - self.assertIn('filename', container) - - def test_inspect_build_type_object(self): - builtin_astroid = MANAGER.ast_from_module_name(BUILTINS) - - infered = list(builtin_astroid.igetattr('object')) - self.assertEqual(len(infered), 1) - infered = infered[0] - self.assertEqual(infered.name, 'object') - infered.as_string() # no crash test - - infered = list(builtin_astroid.igetattr('type')) - self.assertEqual(len(infered), 1) - infered = infered[0] - self.assertEqual(infered.name, 'type') - infered.as_string() # no crash test - - def test_package_name(self): - """test base properties and method of a astroid module""" - datap = self.builder.file_build(join(DATA, '__init__.py'), 'data') - self.assertEqual(datap.name, 'data') - self.assertEqual(datap.package, 1) - datap = self.builder.file_build(join(DATA, '__init__.py'), 'data.__init__') - self.assertEqual(datap.name, 'data') - self.assertEqual(datap.package, 1) - - def test_yield_parent(self): - """check if we added discard nodes as yield parent (w/ compiler)""" - data = """ -def yiell(): - yield 0 - if noe: - yield more -""" - func = self.builder.string_build(data).body[0] - self.assertIsInstance(func, nodes.Function) - stmt = func.body[0] - self.assertIsInstance(stmt, nodes.Discard) - self.assertIsInstance(stmt.value, nodes.Yield) - self.assertIsInstance(func.body[1].body[0], nodes.Discard) - self.assertIsInstance(func.body[1].body[0].value, nodes.Yield) - - def test_object(self): - obj_astroid = self.builder.inspect_build(object) - self.assertIn('__setattr__', obj_astroid) - - def test_newstyle_detection(self): - data = ''' -class A: - "old style" - -class B(A): - "old style" - -class C(object): - "new style" - -class D(C): - "new style" - -__metaclass__ = type - -class E(A): - "old style" - -class F: - "new style" -''' - mod_astroid = self.builder.string_build(data, __name__, __file__) - self.assertFalse(mod_astroid['A'].newstyle) - self.assertFalse(mod_astroid['B'].newstyle) - self.assertTrue(mod_astroid['C'].newstyle) - self.assertTrue(mod_astroid['D'].newstyle) - self.assertFalse(mod_astroid['E'].newstyle) - self.assertTrue(mod_astroid['F'].newstyle) - - def test_globals(self): - data = ''' -CSTE = 1 - -def update_global(): - global CSTE - CSTE += 1 - -def global_no_effect(): - global CSTE2 - print (CSTE) -''' - astroid = self.builder.string_build(data, __name__, __file__) - self.assertEqual(len(astroid.getattr('CSTE')), 2) - self.assertIsInstance(astroid.getattr('CSTE')[0], nodes.AssName) - self.assertEqual(astroid.getattr('CSTE')[0].fromlineno, 2) - self.assertEqual(astroid.getattr('CSTE')[1].fromlineno, 6) - self.assertRaises(NotFoundError, - astroid.getattr, 'CSTE2') - self.assertRaises(InferenceError, - astroid['global_no_effect'].ilookup('CSTE2').next) - - def test_socket_build(self): - import socket - astroid = self.builder.module_build(socket) - # XXX just check the first one. Actually 3 objects are inferred (look at - # the socket module) but the last one as those attributes dynamically - # set and astroid is missing this. - for fclass in astroid.igetattr('socket'): - #print fclass.root().name, fclass.name, fclass.lineno - self.assertIn('connect', fclass) - self.assertIn('send', fclass) - self.assertIn('close', fclass) - break - - def test_gen_expr_var_scope(self): - data = 'l = list(n for n in range(10))\n' - astroid = self.builder.string_build(data, __name__, __file__) - # n unavailable outside gen expr scope - self.assertNotIn('n', astroid) - # test n is inferable anyway - n = get_name_node(astroid, 'n') - self.assertIsNot(n.scope(), astroid) - self.assertEqual([i.__class__ for i in n.infer()], - [YES.__class__]) - -class FileBuildTC(TestCase): - - module = builder.AstroidBuilder().file_build(join(DATA, 'module.py'), 'data.module') - - def test_module_base_props(self): - """test base properties and method of a astroid module""" - module = self.module - self.assertEqual(module.name, 'data.module') - self.assertEqual(module.doc, "test module for astroid\n") - self.assertEqual(module.fromlineno, 0) - self.assertIsNone(module.parent) - self.assertEqual(module.frame(), module) - self.assertEqual(module.root(), module) - self.assertEqual(module.file, join(abspath(data.__path__[0]), 'module.py')) - self.assertEqual(module.pure_python, 1) - self.assertEqual(module.package, 0) - self.assertFalse(module.is_statement) - self.assertEqual(module.statement(), module) - self.assertEqual(module.statement(), module) - - def test_module_locals(self): - """test the 'locals' dictionary of a astroid module""" - module = self.module - _locals = module.locals - self.assertIs(_locals, module.globals) - keys = sorted(_locals.keys()) - should = ['MY_DICT', 'YO', 'YOUPI', - '__revision__', 'global_access','modutils', 'four_args', - 'os', 'redirect', 'spawn', 'LocalsVisitor', 'ASTWalker'] - should.sort() - self.assertEqual(keys, should) - - def test_function_base_props(self): - """test base properties and method of a astroid function""" - module = self.module - function = module['global_access'] - self.assertEqual(function.name, 'global_access') - self.assertEqual(function.doc, 'function test') - self.assertEqual(function.fromlineno, 11) - self.assertTrue(function.parent) - self.assertEqual(function.frame(), function) - self.assertEqual(function.parent.frame(), module) - self.assertEqual(function.root(), module) - self.assertEqual([n.name for n in function.args.args], ['key', 'val']) - self.assertEqual(function.type, 'function') - - def test_function_locals(self): - """test the 'locals' dictionary of a astroid function""" - _locals = self.module['global_access'].locals - self.assertEqual(len(_locals), 4) - keys = sorted(_locals.keys()) - self.assertEqual(keys, ['i', 'key', 'local', 'val']) - - def test_class_base_props(self): - """test base properties and method of a astroid class""" - module = self.module - klass = module['YO'] - self.assertEqual(klass.name, 'YO') - self.assertEqual(klass.doc, 'hehe') - self.assertEqual(klass.fromlineno, 25) - self.assertTrue(klass.parent) - self.assertEqual(klass.frame(), klass) - self.assertEqual(klass.parent.frame(), module) - self.assertEqual(klass.root(), module) - self.assertEqual(klass.basenames, []) - self.assertEqual(klass.newstyle, False) - - def test_class_locals(self): - """test the 'locals' dictionary of a astroid class""" - module = self.module - klass1 = module['YO'] - locals1 = klass1.locals - keys = sorted(locals1.keys()) - self.assertEqual(keys, ['__init__', 'a']) - klass2 = module['YOUPI'] - locals2 = klass2.locals - keys = locals2.keys() - keys.sort() - self.assertEqual(keys, ['__init__', 'class_attr', 'class_method', - 'method', 'static_method']) - - def test_class_instance_attrs(self): - module = self.module - klass1 = module['YO'] - klass2 = module['YOUPI'] - self.assertEqual(klass1.instance_attrs.keys(), ['yo']) - self.assertEqual(klass2.instance_attrs.keys(), ['member']) - - def test_class_basenames(self): - module = self.module - klass1 = module['YO'] - klass2 = module['YOUPI'] - self.assertEqual(klass1.basenames, []) - self.assertEqual(klass2.basenames, ['YO']) - - def test_method_base_props(self): - """test base properties and method of a astroid method""" - klass2 = self.module['YOUPI'] - # "normal" method - method = klass2['method'] - self.assertEqual(method.name, 'method') - self.assertEqual([n.name for n in method.args.args], ['self']) - self.assertEqual(method.doc, 'method test') - self.assertEqual(method.fromlineno, 47) - self.assertEqual(method.type, 'method') - # class method - method = klass2['class_method'] - self.assertEqual([n.name for n in method.args.args], ['cls']) - self.assertEqual(method.type, 'classmethod') - # static method - method = klass2['static_method'] - self.assertEqual(method.args.args, []) - self.assertEqual(method.type, 'staticmethod') - - def test_method_locals(self): - """test the 'locals' dictionary of a astroid method""" - method = self.module['YOUPI']['method'] - _locals = method.locals - keys = sorted(_locals) - if sys.version_info < (3, 0): - self.assertEqual(len(_locals), 5) - self.assertEqual(keys, ['a', 'autre', 'b', 'local', 'self']) - else:# ListComp variables are no more accessible outside - self.assertEqual(len(_locals), 3) - self.assertEqual(keys, ['autre', 'local', 'self']) - - -class ModuleBuildTC(FileBuildTC): - - def setUp(self): - abuilder = builder.AstroidBuilder() - self.module = abuilder.module_build(test_module) - - -class MoreTC(TestCase): - - def setUp(self): - self.builder = builder.AstroidBuilder() - - def test_infered_build(self): - code = '''class A: pass -A.type = "class" - -def A_ass_type(self): - print (self) -A.ass_type = A_ass_type - ''' - astroid = self.builder.string_build(code) - lclass = list(astroid.igetattr('A')) - self.assertEqual(len(lclass), 1) - lclass = lclass[0] - self.assertIn('ass_type', lclass.locals) - self.assertIn('type', lclass.locals) - - def test_augassign_attr(self): - astroid = self.builder.string_build("""class Counter: - v = 0 - def inc(self): - self.v += 1 - """, __name__, __file__) - # Check self.v += 1 generate AugAssign(AssAttr(...)), not AugAssign(GetAttr(AssName...)) - - def test_dumb_module(self): - astroid = self.builder.string_build("pouet") - - def test_infered_dont_pollute(self): - code = ''' -def func(a=None): - a.custom_attr = 0 -def func2(a={}): - a.custom_attr = 0 - ''' - astroid = self.builder.string_build(code) - nonetype = nodes.const_factory(None) - self.assertNotIn('custom_attr', nonetype.locals) - self.assertNotIn('custom_attr', nonetype.instance_attrs) - nonetype = nodes.const_factory({}) - self.assertNotIn('custom_attr', nonetype.locals) - self.assertNotIn('custom_attr', nonetype.instance_attrs) - - - def test_asstuple(self): - code = 'a, b = range(2)' - astroid = self.builder.string_build(code) - self.assertIn('b', astroid.locals) - code = ''' -def visit_if(self, node): - node.test, body = node.tests[0] -''' - astroid = self.builder.string_build(code) - self.assertIn('body', astroid['visit_if'].locals) - - def test_build_constants(self): - '''test expected values of constants after rebuilding''' - code = ''' -def func(): - return None - return - return 'None' -''' - astroid = self.builder.string_build(code) - none, nothing, chain = [ret.value for ret in astroid.body[0].body] - self.assertIsInstance(none, nodes.Const) - self.assertIsNone(none.value) - self.assertIsNone(nothing) - self.assertIsInstance(chain, nodes.Const) - self.assertEqual(chain.value, 'None') - - - def test_lgc_classproperty(self): - '''test expected values of constants after rebuilding''' - code = ''' -from logilab.common.decorators import classproperty - -class A(object): - @classproperty - def hop(cls): - return None -''' - astroid = self.builder.string_build(code) - self.assertEqual(astroid['A']['hop'].type, 'classmethod') - - -if sys.version_info < (3, 0): - guess_encoding = builder._guess_encoding - - class TestGuessEncoding(TestCase): - - def testEmacs(self): - e = guess_encoding('# -*- coding: UTF-8 -*-') - self.assertEqual(e, 'UTF-8') - e = guess_encoding('# -*- coding:UTF-8 -*-') - self.assertEqual(e, 'UTF-8') - e = guess_encoding(''' - ### -*- coding: ISO-8859-1 -*- - ''') - self.assertEqual(e, 'ISO-8859-1') - e = guess_encoding(''' - - ### -*- coding: ISO-8859-1 -*- - ''') - self.assertIsNone(e) - - def testVim(self): - e = guess_encoding('# vim:fileencoding=UTF-8') - self.assertEqual(e, 'UTF-8') - e = guess_encoding(''' - ### vim:fileencoding=ISO-8859-1 - ''') - self.assertEqual(e, 'ISO-8859-1') - e = guess_encoding(''' - - ### vim:fileencoding= ISO-8859-1 - ''') - self.assertIsNone(e) - - def test_wrong_coding(self): - # setting "coding" varaible - e = guess_encoding("coding = UTF-8") - self.assertIsNone(e) - # setting a dictionnary entry - e = guess_encoding("coding:UTF-8") - self.assertIsNone(e) - # setting an arguement - e = guess_encoding("def do_something(a_word_with_coding=None):") - self.assertIsNone(e) - - - def testUTF8(self): - e = guess_encoding('\xef\xbb\xbf any UTF-8 data') - self.assertEqual(e, 'UTF-8') - e = guess_encoding(' any UTF-8 data \xef\xbb\xbf') - self.assertIsNone(e) - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_inference.py astroid-1.3.8/test/unittest_inference.py --- astroid-1.0.1/test/unittest_inference.py 2013-10-18 15:34:05.000000000 +0000 +++ astroid-1.3.8/test/unittest_inference.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1183 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""tests for the astroid inference capabilities -""" -from os.path import join, dirname, abspath -import sys -from StringIO import StringIO - -from logilab.common.testlib import TestCase, unittest_main, require_version - -from astroid import InferenceError, builder, nodes -from astroid.inference import infer_end as inference_infer_end -from astroid.bases import YES, Instance, BoundMethod, UnboundMethod,\ - path_wrapper, BUILTINS - -def get_name_node(start_from, name, index=0): - return [n for n in start_from.nodes_of_class(nodes.Name) if n.name == name][index] - -def get_node_of_class(start_from, klass): - return start_from.nodes_of_class(klass).next() - -builder = builder.AstroidBuilder() - -class InferenceUtilsTC(TestCase): - - def test_path_wrapper(self): - def infer_default(self, *args): - raise InferenceError - infer_default = path_wrapper(infer_default) - infer_end = path_wrapper(inference_infer_end) - self.assertRaises(InferenceError, - infer_default(1).next) - self.assertEqual(infer_end(1).next(), 1) - -if sys.version_info < (3, 0): - EXC_MODULE = 'exceptions' -else: - EXC_MODULE = BUILTINS - -class InferenceTC(TestCase): - - CODE = ''' - -class C(object): - "new style" - attr = 4 - - def meth1(self, arg1, optarg=0): - var = object() - print ("yo", arg1, optarg) - self.iattr = "hop" - return var - - def meth2(self): - self.meth1(*self.meth3) - - def meth3(self, d=attr): - b = self.attr - c = self.iattr - return b, c - -ex = Exception("msg") -v = C().meth1(1) -m_unbound = C.meth1 -m_bound = C().meth1 -a, b, c = ex, 1, "bonjour" -[d, e, f] = [ex, 1.0, ("bonjour", v)] -g, h = f -i, (j, k) = "glup", f - -a, b= b, a # Gasp ! -''' - - astroid = builder.string_build(CODE, __name__, __file__) - - def test_module_inference(self): - infered = self.astroid.infer() - obj = infered.next() - self.assertEqual(obj.name, __name__) - self.assertEqual(obj.root().name, __name__) - self.assertRaises(StopIteration, infered.next) - - def test_class_inference(self): - infered = self.astroid['C'].infer() - obj = infered.next() - self.assertEqual(obj.name, 'C') - self.assertEqual(obj.root().name, __name__) - self.assertRaises(StopIteration, infered.next) - - def test_function_inference(self): - infered = self.astroid['C']['meth1'].infer() - obj = infered.next() - self.assertEqual(obj.name, 'meth1') - self.assertEqual(obj.root().name, __name__) - self.assertRaises(StopIteration, infered.next) - - def test_builtin_name_inference(self): - infered = self.astroid['C']['meth1']['var'].infer() - var = infered.next() - self.assertEqual(var.name, 'object') - self.assertEqual(var.root().name, BUILTINS) - self.assertRaises(StopIteration, infered.next) - - def test_tupleassign_name_inference(self): - infered = self.astroid['a'].infer() - exc = infered.next() - self.assertIsInstance(exc, Instance) - self.assertEqual(exc.name, 'Exception') - self.assertEqual(exc.root().name, EXC_MODULE) - self.assertRaises(StopIteration, infered.next) - infered = self.astroid['b'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, 1) - self.assertRaises(StopIteration, infered.next) - infered = self.astroid['c'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, "bonjour") - self.assertRaises(StopIteration, infered.next) - - def test_listassign_name_inference(self): - infered = self.astroid['d'].infer() - exc = infered.next() - self.assertIsInstance(exc, Instance) - self.assertEqual(exc.name, 'Exception') - self.assertEqual(exc.root().name, EXC_MODULE) - self.assertRaises(StopIteration, infered.next) - infered = self.astroid['e'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, 1.0) - self.assertRaises(StopIteration, infered.next) - infered = self.astroid['f'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Tuple) - self.assertRaises(StopIteration, infered.next) - - def test_advanced_tupleassign_name_inference1(self): - infered = self.astroid['g'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, "bonjour") - self.assertRaises(StopIteration, infered.next) - infered = self.astroid['h'].infer() - var = infered.next() - self.assertEqual(var.name, 'object') - self.assertEqual(var.root().name, BUILTINS) - self.assertRaises(StopIteration, infered.next) - - def test_advanced_tupleassign_name_inference2(self): - infered = self.astroid['i'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, u"glup") - self.assertRaises(StopIteration, infered.next) - infered = self.astroid['j'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, "bonjour") - self.assertRaises(StopIteration, infered.next) - infered = self.astroid['k'].infer() - var = infered.next() - self.assertEqual(var.name, 'object') - self.assertEqual(var.root().name, BUILTINS) - self.assertRaises(StopIteration, infered.next) - - def test_swap_assign_inference(self): - infered = self.astroid.locals['a'][1].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, 1) - self.assertRaises(StopIteration, infered.next) - infered = self.astroid.locals['b'][1].infer() - exc = infered.next() - self.assertIsInstance(exc, Instance) - self.assertEqual(exc.name, 'Exception') - self.assertEqual(exc.root().name, EXC_MODULE) - self.assertRaises(StopIteration, infered.next) - - def test_getattr_inference1(self): - infered = self.astroid['ex'].infer() - exc = infered.next() - self.assertIsInstance(exc, Instance) - self.assertEqual(exc.name, 'Exception') - self.assertEqual(exc.root().name, EXC_MODULE) - self.assertRaises(StopIteration, infered.next) - - def test_getattr_inference2(self): - infered = get_node_of_class(self.astroid['C']['meth2'], nodes.Getattr).infer() - meth1 = infered.next() - self.assertEqual(meth1.name, 'meth1') - self.assertEqual(meth1.root().name, __name__) - self.assertRaises(StopIteration, infered.next) - - def test_getattr_inference3(self): - infered = self.astroid['C']['meth3']['b'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, 4) - self.assertRaises(StopIteration, infered.next) - - def test_getattr_inference4(self): - infered = self.astroid['C']['meth3']['c'].infer() - const = infered.next() - self.assertIsInstance(const, nodes.Const) - self.assertEqual(const.value, "hop") - self.assertRaises(StopIteration, infered.next) - - def test_callfunc_inference(self): - infered = self.astroid['v'].infer() - meth1 = infered.next() - self.assertIsInstance(meth1, Instance) - self.assertEqual(meth1.name, 'object') - self.assertEqual(meth1.root().name, BUILTINS) - self.assertRaises(StopIteration, infered.next) - - def test_unbound_method_inference(self): - infered = self.astroid['m_unbound'].infer() - meth1 = infered.next() - self.assertIsInstance(meth1, UnboundMethod) - self.assertEqual(meth1.name, 'meth1') - self.assertEqual(meth1.parent.frame().name, 'C') - self.assertRaises(StopIteration, infered.next) - - def test_bound_method_inference(self): - infered = self.astroid['m_bound'].infer() - meth1 = infered.next() - self.assertIsInstance(meth1, BoundMethod) - self.assertEqual(meth1.name, 'meth1') - self.assertEqual(meth1.parent.frame().name, 'C') - self.assertRaises(StopIteration, infered.next) - - def test_args_default_inference1(self): - optarg = get_name_node(self.astroid['C']['meth1'], 'optarg') - infered = optarg.infer() - obj1 = infered.next() - self.assertIsInstance(obj1, nodes.Const) - self.assertEqual(obj1.value, 0) - obj1 = infered.next() - self.assertIs(obj1, YES, obj1) - self.assertRaises(StopIteration, infered.next) - - def test_args_default_inference2(self): - infered = self.astroid['C']['meth3'].ilookup('d') - obj1 = infered.next() - self.assertIsInstance(obj1, nodes.Const) - self.assertEqual(obj1.value, 4) - obj1 = infered.next() - self.assertIs(obj1, YES, obj1) - self.assertRaises(StopIteration, infered.next) - - def test_inference_restrictions(self): - infered = get_name_node(self.astroid['C']['meth1'], 'arg1').infer() - obj1 = infered.next() - self.assertIs(obj1, YES, obj1) - self.assertRaises(StopIteration, infered.next) - - def test_ancestors_inference(self): - code = ''' -class A: - pass - -class A(A): - pass - ''' - astroid = builder.string_build(code, __name__, __file__) - a1 = astroid.locals['A'][0] - a2 = astroid.locals['A'][1] - a2_ancestors = list(a2.ancestors()) - self.assertEqual(len(a2_ancestors), 1) - self.assertIs(a2_ancestors[0], a1) - - def test_ancestors_inference2(self): - code = ''' -class A: - pass - -class B(A): pass - -class A(B): - pass - ''' - astroid = builder.string_build(code, __name__, __file__) - a1 = astroid.locals['A'][0] - a2 = astroid.locals['A'][1] - a2_ancestors = list(a2.ancestors()) - self.assertEqual(len(a2_ancestors), 2) - self.assertIs(a2_ancestors[0], astroid.locals['B'][0]) - self.assertIs(a2_ancestors[1], a1) - - - def test_f_arg_f(self): - code = ''' -def f(f=1): - return f - -a = f() - ''' - astroid = builder.string_build(code, __name__, __file__) - a = astroid['a'] - a_infered = a.infered() - self.assertEqual(a_infered[0].value, 1) - self.assertEqual(len(a_infered), 1) - - def test_exc_ancestors(self): - code = ''' -def f(): - raise NotImplementedError - ''' - astroid = builder.string_build(code, __name__, __file__) - error = astroid.nodes_of_class(nodes.Name).next() - nie = error.infered()[0] - self.assertIsInstance(nie, nodes.Class) - nie_ancestors = [c.name for c in nie.ancestors()] - if sys.version_info < (3, 0): - self.assertEqual(nie_ancestors, ['RuntimeError', 'StandardError', 'Exception', 'BaseException', 'object']) - else: - self.assertEqual(nie_ancestors, ['RuntimeError', 'Exception', 'BaseException', 'object']) - - def test_except_inference(self): - code = ''' -try: - print (hop) -except NameError, ex: - ex1 = ex -except Exception, ex: - ex2 = ex - raise - ''' - if sys.version_info >= (3, 0): - code = code.replace(', ex:', ' as ex:') - astroid = builder.string_build(code, __name__, __file__) - ex1 = astroid['ex1'] - ex1_infer = ex1.infer() - ex1 = ex1_infer.next() - self.assertIsInstance(ex1, Instance) - self.assertEqual(ex1.name, 'NameError') - self.assertRaises(StopIteration, ex1_infer.next) - ex2 = astroid['ex2'] - ex2_infer = ex2.infer() - ex2 = ex2_infer.next() - self.assertIsInstance(ex2, Instance) - self.assertEqual(ex2.name, 'Exception') - self.assertRaises(StopIteration, ex2_infer.next) - - def test_del1(self): - code = ''' -del undefined_attr - ''' - delete = builder.string_build(code, __name__, __file__).body[0] - self.assertRaises(InferenceError, delete.infer) - - def test_del2(self): - code = ''' -a = 1 -b = a -del a -c = a -a = 2 -d = a - ''' - astroid = builder.string_build(code, __name__, __file__) - n = astroid['b'] - n_infer = n.infer() - infered = n_infer.next() - self.assertIsInstance(infered, nodes.Const) - self.assertEqual(infered.value, 1) - self.assertRaises(StopIteration, n_infer.next) - n = astroid['c'] - n_infer = n.infer() - self.assertRaises(InferenceError, n_infer.next) - n = astroid['d'] - n_infer = n.infer() - infered = n_infer.next() - self.assertIsInstance(infered, nodes.Const) - self.assertEqual(infered.value, 2) - self.assertRaises(StopIteration, n_infer.next) - - def test_builtin_types(self): - code = ''' -l = [1] -t = (2,) -d = {} -s = '' -s2 = '_' - ''' - astroid = builder.string_build(code, __name__, __file__) - n = astroid['l'] - infered = n.infer().next() - self.assertIsInstance(infered, nodes.List) - self.assertIsInstance(infered, Instance) - self.assertEqual(infered.getitem(0).value, 1) - self.assertIsInstance(infered._proxied, nodes.Class) - self.assertEqual(infered._proxied.name, 'list') - self.assertIn('append', infered._proxied.locals) - n = astroid['t'] - infered = n.infer().next() - self.assertIsInstance(infered, nodes.Tuple) - self.assertIsInstance(infered, Instance) - self.assertEqual(infered.getitem(0).value, 2) - self.assertIsInstance(infered._proxied, nodes.Class) - self.assertEqual(infered._proxied.name, 'tuple') - n = astroid['d'] - infered = n.infer().next() - self.assertIsInstance(infered, nodes.Dict) - self.assertIsInstance(infered, Instance) - self.assertIsInstance(infered._proxied, nodes.Class) - self.assertEqual(infered._proxied.name, 'dict') - self.assertIn('get', infered._proxied.locals) - n = astroid['s'] - infered = n.infer().next() - self.assertIsInstance(infered, nodes.Const) - self.assertIsInstance(infered, Instance) - self.assertEqual(infered.name, 'str') - self.assertIn('lower', infered._proxied.locals) - n = astroid['s2'] - infered = n.infer().next() - self.assertEqual(infered.getitem(0).value, '_') - - @require_version('2.7') - def test_builtin_types_py27(self): - code = 's = {1}' - astroid = builder.string_build(code, __name__, __file__) - n = astroid['s'] - infered = n.infer().next() - self.assertIsInstance(infered, nodes.Set) - self.assertIsInstance(infered, Instance) - self.assertEqual(infered.name, 'set') - self.assertIn('remove', infered._proxied.locals) - - def test_unicode_type(self): - if sys.version_info >= (3, 0): - self.skipTest('unicode removed on py >= 3.0') - code = '''u = u""''' - astroid = builder.string_build(code, __name__, __file__) - n = astroid['u'] - infered = n.infer().next() - self.assertIsInstance(infered, nodes.Const) - self.assertIsInstance(infered, Instance) - self.assertEqual(infered.name, 'unicode') - self.assertIn('lower', infered._proxied.locals) - - def test_descriptor_are_callable(self): - code = ''' -class A: - statm = staticmethod(open) - clsm = classmethod('whatever') - ''' - astroid = builder.string_build(code, __name__, __file__) - statm = astroid['A'].igetattr('statm').next() - self.assertTrue(statm.callable()) - clsm = astroid['A'].igetattr('clsm').next() - self.assertTrue(clsm.callable()) - - def test_bt_ancestor_crash(self): - code = ''' -class Warning(Warning): - pass - ''' - astroid = builder.string_build(code, __name__, __file__) - w = astroid['Warning'] - ancestors = w.ancestors() - ancestor = ancestors.next() - self.assertEqual(ancestor.name, 'Warning') - self.assertEqual(ancestor.root().name, EXC_MODULE) - ancestor = ancestors.next() - self.assertEqual(ancestor.name, 'Exception') - self.assertEqual(ancestor.root().name, EXC_MODULE) - ancestor = ancestors.next() - self.assertEqual(ancestor.name, 'BaseException') - self.assertEqual(ancestor.root().name, EXC_MODULE) - ancestor = ancestors.next() - self.assertEqual(ancestor.name, 'object') - self.assertEqual(ancestor.root().name, BUILTINS) - self.assertRaises(StopIteration, ancestors.next) - - def test_qqch(self): - code = ''' -from logilab.common.modutils import load_module_from_name -xxx = load_module_from_name('__pkginfo__') - ''' - astroid = builder.string_build(code, __name__, __file__) - xxx = astroid['xxx'] - self.assertSetEqual(set(n.__class__ for n in xxx.infered()), - set([nodes.Const, YES.__class__])) - - def test_method_argument(self): - code = ''' -class ErudiEntitySchema: - """a entity has a type, a set of subject and or object relations""" - def __init__(self, e_type, **kwargs): - kwargs['e_type'] = e_type.capitalize().encode() - - def meth(self, e_type, *args, **kwargs): - kwargs['e_type'] = e_type.capitalize().encode() - print(args) - ''' - astroid = builder.string_build(code, __name__, __file__) - arg = get_name_node(astroid['ErudiEntitySchema']['__init__'], 'e_type') - self.assertEqual([n.__class__ for n in arg.infer()], - [YES.__class__]) - arg = get_name_node(astroid['ErudiEntitySchema']['__init__'], 'kwargs') - self.assertEqual([n.__class__ for n in arg.infer()], - [nodes.Dict]) - arg = get_name_node(astroid['ErudiEntitySchema']['meth'], 'e_type') - self.assertEqual([n.__class__ for n in arg.infer()], - [YES.__class__]) - arg = get_name_node(astroid['ErudiEntitySchema']['meth'], 'args') - self.assertEqual([n.__class__ for n in arg.infer()], - [nodes.Tuple]) - arg = get_name_node(astroid['ErudiEntitySchema']['meth'], 'kwargs') - self.assertEqual([n.__class__ for n in arg.infer()], - [nodes.Dict]) - - - def test_tuple_then_list(self): - code = ''' -def test_view(rql, vid, tags=()): - tags = list(tags) - tags.append(vid) - ''' - astroid = builder.string_build(code, __name__, __file__) - name = get_name_node(astroid['test_view'], 'tags', -1) - it = name.infer() - tags = it.next() - self.assertEqual(tags.__class__, Instance) - self.assertEqual(tags._proxied.name, 'list') - self.assertRaises(StopIteration, it.next) - - - - def test_mulassign_inference(self): - code = ''' - -def first_word(line): - """Return the first word of a line""" - - return line.split()[0] - -def last_word(line): - """Return last word of a line""" - - return line.split()[-1] - -def process_line(word_pos): - """Silly function: returns (ok, callable) based on argument. - - For test purpose only. - """ - - if word_pos > 0: - return (True, first_word) - elif word_pos < 0: - return (True, last_word) - else: - return (False, None) - -if __name__ == '__main__': - - line_number = 0 - for a_line in file('test_callable.py'): - tupletest = process_line(line_number) - (ok, fct) = process_line(line_number) - if ok: - fct(a_line) -''' - astroid = builder.string_build(code, __name__, __file__) - self.assertEqual(len(list(astroid['process_line'].infer_call_result( - None))), 3) - self.assertEqual(len(list(astroid['tupletest'].infer())), 3) - values = ['Function(first_word)', 'Function(last_word)', 'Const(NoneType)'] - self.assertEqual([str(infered) - for infered in astroid['fct'].infer()], values) - - def test_float_complex_ambiguity(self): - code = ''' -def no_conjugate_member(magic_flag): - """should not raise E1101 on something.conjugate""" - if magic_flag: - something = 1.0 - else: - something = 1.0j - if isinstance(something, float): - return something - return something.conjugate() - ''' - astroid = builder.string_build(code, __name__, __file__) - self.assertEqual([i.value for i in - astroid['no_conjugate_member'].ilookup('something')], [1.0, 1.0j]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'something', -1).infer()], [1.0, 1.0j]) - - def test_lookup_cond_branches(self): - code = ''' -def no_conjugate_member(magic_flag): - """should not raise E1101 on something.conjugate""" - something = 1.0 - if magic_flag: - something = 1.0j - return something.conjugate() - ''' - astroid = builder.string_build(code, __name__, __file__) - self.assertEqual([i.value for i in - get_name_node(astroid, 'something', -1).infer()], [1.0, 1.0j]) - - - def test_simple_subscript(self): - code = ''' -a = [1, 2, 3][0] -b = (1, 2, 3)[1] -c = (1, 2, 3)[-1] -d = a + b + c -print (d) -e = {'key': 'value'} -f = e['key'] -print (f) - ''' - astroid = builder.string_build(code, __name__, __file__) - self.assertEqual([i.value for i in - get_name_node(astroid, 'a', -1).infer()], [1]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'b', -1).infer()], [2]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'c', -1).infer()], [3]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'd', -1).infer()], [6]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'f', -1).infer()], ['value']) - - #def test_simple_tuple(self): - #"""test case for a simple tuple value""" - ## XXX tuple inference is not implemented ... - #code = """ -#a = (1,) -#b = (22,) -#some = a + b -#""" - #astroid = builder.string_build(code, __name__, __file__) - #self.assertEqual(astroid['some'].infer.next().as_string(), "(1, 22)") - - def test_simple_for(self): - code = ''' -for a in [1, 2, 3]: - print (a) -for b,c in [(1,2), (3,4)]: - print (b) - print (c) - -print ([(d,e) for e,d in ([1,2], [3,4])]) - ''' - astroid = builder.string_build(code, __name__, __file__) - self.assertEqual([i.value for i in - get_name_node(astroid, 'a', -1).infer()], [1, 2, 3]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'b', -1).infer()], [1, 3]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'c', -1).infer()], [2, 4]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'd', -1).infer()], [2, 4]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'e', -1).infer()], [1, 3]) - - - def test_simple_for_genexpr(self): - code = ''' -print ((d,e) for e,d in ([1,2], [3,4])) - ''' - astroid = builder.string_build(code, __name__, __file__) - self.assertEqual([i.value for i in - get_name_node(astroid, 'd', -1).infer()], [2, 4]) - self.assertEqual([i.value for i in - get_name_node(astroid, 'e', -1).infer()], [1, 3]) - - - def test_builtin_help(self): - code = ''' -help() - ''' - # XXX failing since __builtin__.help assignment has - # been moved into a function... - astroid = builder.string_build(code, __name__, __file__) - node = get_name_node(astroid, 'help', -1) - infered = list(node.infer()) - self.assertEqual(len(infered), 1, infered) - self.assertIsInstance(infered[0], Instance) - self.assertEqual(str(infered[0]), - 'Instance of site._Helper') - - def test_builtin_open(self): - code = ''' -open("toto.txt") - ''' - astroid = builder.string_build(code, __name__, __file__) - node = get_name_node(astroid, 'open', -1) - infered = list(node.infer()) - self.assertEqual(len(infered), 1) - if hasattr(sys, 'pypy_version_info'): - self.assertIsInstance(infered[0], nodes.Class) - self.assertEqual(infered[0].name, 'file') - else: - self.assertIsInstance(infered[0], nodes.Function) - self.assertEqual(infered[0].name, 'open') - - def test_callfunc_context_func(self): - code = ''' -def mirror(arg=None): - return arg - -un = mirror(1) - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid.igetattr('un')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Const) - self.assertEqual(infered[0].value, 1) - - def test_callfunc_context_lambda(self): - code = ''' -mirror = lambda x=None: x - -un = mirror(1) - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid.igetattr('mirror')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Lambda) - infered = list(astroid.igetattr('un')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Const) - self.assertEqual(infered[0].value, 1) - - def test_factory_method(self): - code = ''' -class Super(object): - @classmethod - def instance(cls): - return cls() - -class Sub(Super): - def method(self): - print ('method called') - -sub = Sub.instance() - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid.igetattr('sub')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], Instance) - self.assertEqual(infered[0]._proxied.name, 'Sub') - - - def test_import_as(self): - code = ''' -import os.path as osp -print (osp.dirname(__file__)) - -from os.path import exists as e -assert e(__file__) - -from new import code as make_code -print (make_code) - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid.igetattr('osp')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Module) - self.assertEqual(infered[0].name, 'os.path') - infered = list(astroid.igetattr('e')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Function) - self.assertEqual(infered[0].name, 'exists') - if sys.version_info >= (3, 0): - self.skipTest(' module has been removed') - infered = list(astroid.igetattr('make_code')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], Instance) - self.assertEqual(str(infered[0]), - 'Instance of %s.type' % BUILTINS) - - def _test_const_infered(self, node, value): - infered = list(node.infer()) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Const) - self.assertEqual(infered[0].value, value) - - def test_unary_not(self): - for code in ('a = not (1,); b = not ()', - 'a = not {1:2}; b = not {}'): - astroid = builder.string_build(code, __name__, __file__) - self._test_const_infered(astroid['a'], False) - self._test_const_infered(astroid['b'], True) - - def test_binary_op_int_add(self): - astroid = builder.string_build('a = 1 + 2', __name__, __file__) - self._test_const_infered(astroid['a'], 3) - - def test_binary_op_int_sub(self): - astroid = builder.string_build('a = 1 - 2', __name__, __file__) - self._test_const_infered(astroid['a'], -1) - - def test_binary_op_float_div(self): - astroid = builder.string_build('a = 1 / 2.', __name__, __file__) - self._test_const_infered(astroid['a'], 1 / 2.) - - def test_binary_op_str_mul(self): - astroid = builder.string_build('a = "*" * 40', __name__, __file__) - self._test_const_infered(astroid['a'], "*" * 40) - - def test_binary_op_bitand(self): - astroid = builder.string_build('a = 23&20', __name__, __file__) - self._test_const_infered(astroid['a'], 23&20) - - def test_binary_op_bitor(self): - astroid = builder.string_build('a = 23|8', __name__, __file__) - self._test_const_infered(astroid['a'], 23|8) - - def test_binary_op_bitxor(self): - astroid = builder.string_build('a = 23^9', __name__, __file__) - self._test_const_infered(astroid['a'], 23^9) - - def test_binary_op_shiftright(self): - astroid = builder.string_build('a = 23 >>1', __name__, __file__) - self._test_const_infered(astroid['a'], 23>>1) - - def test_binary_op_shiftleft(self): - astroid = builder.string_build('a = 23 <<1', __name__, __file__) - self._test_const_infered(astroid['a'], 23<<1) - - - def test_binary_op_list_mul(self): - for code in ('a = [[]] * 2', 'a = 2 * [[]]'): - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid['a'].infer()) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.List) - self.assertEqual(len(infered[0].elts), 2) - self.assertIsInstance(infered[0].elts[0], nodes.List) - self.assertIsInstance(infered[0].elts[1], nodes.List) - - def test_binary_op_list_mul_none(self): - 'test correct handling on list multiplied by None' - astroid = builder.string_build( 'a = [1] * None\nb = [1] * "r"') - infered = astroid['a'].infered() - self.assertEqual(len(infered), 1) - self.assertEqual(infered[0], YES) - infered = astroid['b'].infered() - self.assertEqual(len(infered), 1) - self.assertEqual(infered[0], YES) - - - def test_binary_op_tuple_add(self): - astroid = builder.string_build('a = (1,) + (2,)', __name__, __file__) - infered = list(astroid['a'].infer()) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Tuple) - self.assertEqual(len(infered[0].elts), 2) - self.assertEqual(infered[0].elts[0].value, 1) - self.assertEqual(infered[0].elts[1].value, 2) - - def test_binary_op_custom_class(self): - code = ''' -class myarray: - def __init__(self, array): - self.array = array - def __mul__(self, x): - return myarray([2,4,6]) - def astype(self): - return "ASTYPE" - -def randint(maximum): - if maximum is not None: - return myarray([1,2,3]) * 2 - else: - return int(5) - -x = randint(1) - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid.igetattr('x')) - self.assertEqual(len(infered), 2) - value = [str(v) for v in infered] - # The __name__ trick here makes it work when invoked directly - # (__name__ == '__main__') and through pytest (__name__ == - # 'unittest_inference') - self.assertEqual(value, ['Instance of %s.myarray' % __name__, - 'Instance of %s.int' % BUILTINS]) - - def test_nonregr_lambda_arg(self): - code = ''' -def f(g = lambda: None): - g().x -''' - astroid = builder.string_build(code, __name__, __file__) - callfuncnode = astroid['f'].body[0].value.expr - infered = list(callfuncnode.infer()) - self.assertEqual(len(infered), 2, infered) - infered.remove(YES) - self.assertIsInstance(infered[0], nodes.Const) - self.assertIsNone(infered[0].value) - - def test_nonregr_getitem_empty_tuple(self): - code = ''' -def f(x): - a = ()[x] - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid['f'].ilookup('a')) - self.assertEqual(len(infered), 1) - self.assertEqual(infered[0], YES) - - def test_python25_generator_exit(self): - sys.stderr = StringIO() - data = "b = {}[str(0)+''].a" - astroid = builder.string_build(data, __name__, __file__) - list(astroid['b'].infer()) - output = sys.stderr.getvalue() - # I have no idea how to test for this in another way... - self.assertNotIn("RuntimeError", output, "Exception exceptions.RuntimeError: 'generator ignored GeneratorExit' in ignored") - sys.stderr = sys.__stderr__ - - def test_python25_relative_import(self): - data = "from ...logilab.common import date; print (date)" - # !! FIXME also this relative import would not work 'in real' (no __init__.py in test/) - # the test works since we pretend we have a package by passing the full modname - astroid = builder.string_build(data, 'astroid.test.unittest_inference', __file__) - infered = get_name_node(astroid, 'date').infer().next() - self.assertIsInstance(infered, nodes.Module) - self.assertEqual(infered.name, 'logilab.common.date') - - def test_python25_no_relative_import(self): - fname = join(abspath(dirname(__file__)), 'regrtest_data', 'package', 'absimport.py') - astroid = builder.file_build(fname, 'absimport') - self.assertTrue(astroid.absolute_import_activated(), True) - infered = get_name_node(astroid, 'import_package_subpackage_module').infer().next() - # failed to import since absolute_import is activated - self.assertIs(infered, YES) - - def test_nonregr_absolute_import(self): - fname = join(abspath(dirname(__file__)), 'regrtest_data', 'absimp', 'string.py') - astroid = builder.file_build(fname, 'absimp.string') - self.assertTrue(astroid.absolute_import_activated(), True) - infered = get_name_node(astroid, 'string').infer().next() - self.assertIsInstance(infered, nodes.Module) - self.assertEqual(infered.name, 'string') - self.assertIn('ascii_letters', infered.locals) - - def test_mechanize_open(self): - try: - import mechanize - except ImportError: - self.skipTest('require mechanize installed') - data = '''from mechanize import Browser -print (Browser) -b = Browser() -''' - astroid = builder.string_build(data, __name__, __file__) - browser = get_name_node(astroid, 'Browser').infer().next() - self.assertIsInstance(browser, nodes.Class) - bopen = list(browser.igetattr('open')) - self.skipTest('the commit said: "huum, see that later"') - self.assertEqual(len(bopen), 1) - self.assertIsInstance(bopen[0], nodes.Function) - self.assertTrue(bopen[0].callable()) - b = get_name_node(astroid, 'b').infer().next() - self.assertIsInstance(b, Instance) - bopen = list(b.igetattr('open')) - self.assertEqual(len(bopen), 1) - self.assertIsInstance(bopen[0], BoundMethod) - self.assertTrue(bopen[0].callable()) - - def test_property(self): - code = ''' -from smtplib import SMTP -class SendMailController(object): - - @property - def smtp(self): - return SMTP(mailhost, port) - - @property - def me(self): - return self - -my_smtp = SendMailController().smtp -my_me = SendMailController().me -''' - decorators = set(['%s.property' % BUILTINS]) - astroid = builder.string_build(code, __name__, __file__) - self.assertEqual(astroid['SendMailController']['smtp'].decoratornames(), - decorators) - propinfered = list(astroid.body[2].value.infer()) - self.assertEqual(len(propinfered), 1) - propinfered = propinfered[0] - self.assertIsInstance(propinfered, Instance) - self.assertEqual(propinfered.name, 'SMTP') - self.assertEqual(propinfered.root().name, 'smtplib') - self.assertEqual(astroid['SendMailController']['me'].decoratornames(), - decorators) - propinfered = list(astroid.body[3].value.infer()) - self.assertEqual(len(propinfered), 1) - propinfered = propinfered[0] - self.assertIsInstance(propinfered, Instance) - self.assertEqual(propinfered.name, 'SendMailController') - self.assertEqual(propinfered.root().name, __name__) - - - def test_im_func_unwrap(self): - code = ''' -class EnvBasedTC: - def pactions(self): - pass -pactions = EnvBasedTC.pactions.im_func -print (pactions) - -class EnvBasedTC2: - pactions = EnvBasedTC.pactions.im_func - print (pactions) - -''' - astroid = builder.string_build(code, __name__, __file__) - pactions = get_name_node(astroid, 'pactions') - infered = list(pactions.infer()) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Function) - pactions = get_name_node(astroid['EnvBasedTC2'], 'pactions') - infered = list(pactions.infer()) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Function) - - def test_augassign(self): - code = ''' -a = 1 -a += 2 -print (a) -''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(get_name_node(astroid, 'a').infer()) - - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], nodes.Const) - self.assertEqual(infered[0].value, 3) - - def test_nonregr_func_arg(self): - code = ''' -def foo(self, bar): - def baz(): - pass - def qux(): - return baz - spam = bar(None, qux) - print (spam) -''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(get_name_node(astroid['foo'], 'spam').infer()) - self.assertEqual(len(infered), 1) - self.assertIs(infered[0], YES) - - def test_nonregr_func_global(self): - code = ''' -active_application = None - -def get_active_application(): - global active_application - return active_application - -class Application(object): - def __init__(self): - global active_application - active_application = self - -class DataManager(object): - def __init__(self, app=None): - self.app = get_active_application() - def test(self): - p = self.app - print (p) - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(Instance(astroid['DataManager']).igetattr('app')) - self.assertEqual(len(infered), 2, infered) # None / Instance(Application) - infered = list(get_name_node(astroid['DataManager']['test'], 'p').infer()) - self.assertEqual(len(infered), 2, infered) - for node in infered: - if isinstance(node, Instance) and node.name == 'Application': - break - else: - self.fail('expected to find an instance of Application in %s' % infered) - - def test_list_inference(self): - """#20464""" - code = ''' -import optparse - -A = [] -B = [] - -def test(): - xyz = [ - "foobar=%s" % options.ca, - ] + A + B - - if options.bind is not None: - xyz.append("bind=%s" % options.bind) - return xyz - -def main(): - global options - - parser = optparse.OptionParser() - (options, args) = parser.parse_args() - -Z = test() - ''' - astroid = builder.string_build(code, __name__, __file__) - infered = list(astroid['Z'].infer()) - self.assertEqual(len(infered), 1, infered) - self.assertIsInstance(infered[0], Instance) - self.assertIsInstance(infered[0]._proxied, nodes.Class) - self.assertEqual(infered[0]._proxied.name, 'list') - - def test__new__(self): - code = ''' -class NewTest(object): - "doc" - def __new__(cls, arg): - self = object.__new__(cls) - self.arg = arg - return self - -n = NewTest() - ''' - astroid = builder.string_build(code, __name__, __file__) - self.assertRaises(InferenceError, list, astroid['NewTest'].igetattr('arg')) - n = astroid['n'].infer().next() - infered = list(n.igetattr('arg')) - self.assertEqual(len(infered), 1, infered) - - - def test_two_parents_from_same_module(self): - code = ''' -from data import nonregr -class Xxx(nonregr.Aaa, nonregr.Ccc): - "doc" - ''' - astroid = builder.string_build(code, __name__, __file__) - parents = list(astroid['Xxx'].ancestors()) - self.assertEqual(len(parents), 3, parents) # Aaa, Ccc, object - - def test_pluggable_inference(self): - code = ''' -from collections import namedtuple -A = namedtuple('A', ['a', 'b']) -B = namedtuple('B', 'a b') - ''' - astroid = builder.string_build(code, __name__, __file__) - aclass = astroid['A'].infered()[0] - self.assertIsInstance(aclass, nodes.Class) - self.assertIn('a', aclass.instance_attrs) - self.assertIn('b', aclass.instance_attrs) - bclass = astroid['B'].infered()[0] - self.assertIsInstance(bclass, nodes.Class) - self.assertIn('a', bclass.instance_attrs) - self.assertIn('b', bclass.instance_attrs) - - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_inspector.py astroid-1.3.8/test/unittest_inspector.py --- astroid-1.0.1/test/unittest_inspector.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_inspector.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). -# http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -""" - for the visitors.diadefs module -""" - -import sys -from os.path import join, abspath, dirname - -from logilab.common.testlib import TestCase, unittest_main - -from astroid import nodes, inspector -from astroid.bases import Instance, YES - -from astroid.manager import AstroidManager, _silent_no_wrap - -MANAGER = AstroidManager() - -def astroid_wrapper(func, modname): - return func(modname) - - -DATA2 = join(dirname(abspath(__file__)), 'data2') - - -class LinkerTC(TestCase): - - def setUp(self): - self.project = MANAGER.project_from_files([DATA2], astroid_wrapper) - self.linker = inspector.Linker(self.project) - self.linker.visit(self.project) - - def test_class_implements(self): - klass = self.project.get_module('data2.clientmodule_test')['Ancestor'] - self.assertTrue(hasattr(klass, 'implements')) - self.assertEqual(len(klass.implements), 1) - self.assertTrue(isinstance(klass.implements[0], nodes.Class)) - self.assertEqual(klass.implements[0].name, "Interface") - klass = self.project.get_module('data2.clientmodule_test')['Specialization'] - self.assertTrue(hasattr(klass, 'implements')) - self.assertEqual(len(klass.implements), 0) - - def test_locals_assignment_resolution(self): - klass = self.project.get_module('data2.clientmodule_test')['Specialization'] - self.assertTrue(hasattr(klass, 'locals_type')) - type_dict = klass.locals_type - self.assertEqual(len(type_dict), 2) - keys = sorted(type_dict.keys()) - self.assertEqual(keys, ['TYPE', 'top']) - self.assertEqual(len(type_dict['TYPE']), 1) - self.assertEqual(type_dict['TYPE'][0].value, 'final class') - self.assertEqual(len(type_dict['top']), 1) - self.assertEqual(type_dict['top'][0].value, 'class') - - def test_instance_attrs_resolution(self): - klass = self.project.get_module('data2.clientmodule_test')['Specialization'] - self.assertTrue(hasattr(klass, 'instance_attrs_type')) - type_dict = klass.instance_attrs_type - self.assertEqual(len(type_dict), 3) - keys = sorted(type_dict.keys()) - self.assertEqual(keys, ['_id', 'relation', 'toto']) - self.assertTrue(isinstance(type_dict['relation'][0], Instance), type_dict['relation']) - self.assertEqual(type_dict['relation'][0].name, 'DoNothing') - self.assertTrue(isinstance(type_dict['toto'][0], Instance), type_dict['toto']) - self.assertEqual(type_dict['toto'][0].name, 'Toto') - self.assertIs(type_dict['_id'][0], YES) - - -class LinkerTC2(LinkerTC): - - def setUp(self): - self.project = MANAGER.project_from_files([DATA2], func_wrapper=_silent_no_wrap) - self.linker = inspector.Linker(self.project) - self.linker.visit(self.project) - -__all__ = ('LinkerTC', 'LinkerTC2') - - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_lookup.py astroid-1.3.8/test/unittest_lookup.py --- astroid-1.0.1/test/unittest_lookup.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_lookup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,360 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""tests for the astroid variable lookup capabilities -""" -import sys -from os.path import join, abspath, dirname - -from logilab.common.testlib import TestCase, unittest_main, require_version - -from astroid import builder, nodes, scoped_nodes, \ - InferenceError, NotFoundError, UnresolvableName -from astroid.scoped_nodes import builtin_lookup, Function -from astroid.bases import YES -from unittest_inference import get_name_node - -builder = builder.AstroidBuilder() -DATA = join(dirname(abspath(__file__)), 'data') -MODULE = builder.file_build(join(DATA, 'module.py'), 'data.module') -MODULE2 = builder.file_build(join(DATA, 'module2.py'), 'data.module2') -NONREGR = builder.file_build(join(DATA, 'nonregr.py'), 'data.nonregr') - -class LookupTC(TestCase): - - def test_limit(self): - code = ''' -l = [a - for a,b in list] - -a = 1 -b = a -a = None - -def func(): - c = 1 - ''' - astroid = builder.string_build(code, __name__, __file__) - # a & b - a = astroid.nodes_of_class(nodes.Name).next() - self.assertEqual(a.lineno, 2) - if sys.version_info < (3, 0): - self.assertEqual(len(astroid.lookup('b')[1]), 2) - self.assertEqual(len(astroid.lookup('a')[1]), 3) - b = astroid.locals['b'][1] - else: - self.assertEqual(len(astroid.lookup('b')[1]), 1) - self.assertEqual(len(astroid.lookup('a')[1]), 2) - b = astroid.locals['b'][0] - stmts = a.lookup('a')[1] - self.assertEqual(len(stmts), 1) - self.assertEqual(b.lineno, 6) - b_infer = b.infer() - b_value = b_infer.next() - self.assertEqual(b_value.value, 1) - # c - self.assertRaises(StopIteration, b_infer.next) - func = astroid.locals['func'][0] - self.assertEqual(len(func.lookup('c')[1]), 1) - - def test_module(self): - astroid = builder.string_build('pass', __name__, __file__) - # built-in objects - none = astroid.ilookup('None').next() - self.assertIsNone(none.value) - obj = astroid.ilookup('object').next() - self.assertIsInstance(obj, nodes.Class) - self.assertEqual(obj.name, 'object') - self.assertRaises(InferenceError, astroid.ilookup('YOAA').next) - - # XXX - self.assertEqual(len(list(NONREGR.ilookup('enumerate'))), 2) - - def test_class_ancestor_name(self): - code = ''' -class A: - pass - -class A(A): - pass - ''' - astroid = builder.string_build(code, __name__, __file__) - cls1 = astroid.locals['A'][0] - cls2 = astroid.locals['A'][1] - name = cls2.nodes_of_class(nodes.Name).next() - self.assertEqual(name.infer().next(), cls1) - - ### backport those test to inline code - def test_method(self): - method = MODULE['YOUPI']['method'] - my_dict = method.ilookup('MY_DICT').next() - self.assertTrue(isinstance(my_dict, nodes.Dict), my_dict) - none = method.ilookup('None').next() - self.assertIsNone(none.value) - self.assertRaises(InferenceError, method.ilookup('YOAA').next) - - - def test_function_argument_with_default(self): - make_class = MODULE2['make_class'] - base = make_class.ilookup('base').next() - self.assertTrue(isinstance(base, nodes.Class), base.__class__) - self.assertEqual(base.name, 'YO') - self.assertEqual(base.root().name, 'data.module') - - - def test_class(self): - klass = MODULE['YOUPI'] - my_dict = klass.ilookup('MY_DICT').next() - self.assertIsInstance(my_dict, nodes.Dict) - none = klass.ilookup('None').next() - self.assertIsNone(none.value) - obj = klass.ilookup('object').next() - self.assertIsInstance(obj, nodes.Class) - self.assertEqual(obj.name, 'object') - self.assertRaises(InferenceError, klass.ilookup('YOAA').next) - - - def test_inner_classes(self): - ddd = list(NONREGR['Ccc'].ilookup('Ddd')) - self.assertEqual(ddd[0].name, 'Ddd') - - - def test_loopvar_hiding(self): - astroid = builder.string_build(""" -x = 10 -for x in range(5): - print (x) - -if x > 0: - print ('#' * x) - """, __name__, __file__) - xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'x'] - # inside the loop, only one possible assignment - self.assertEqual(len(xnames[0].lookup('x')[1]), 1) - # outside the loop, two possible assignments - self.assertEqual(len(xnames[1].lookup('x')[1]), 2) - self.assertEqual(len(xnames[2].lookup('x')[1]), 2) - - def test_list_comps(self): - astroid = builder.string_build(""" -print ([ i for i in range(10) ]) -print ([ i for i in range(10) ]) -print ( list( i for i in range(10) ) ) - """, __name__, __file__) - xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'i'] - self.assertEqual(len(xnames[0].lookup('i')[1]), 1) - self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) - self.assertEqual(len(xnames[1].lookup('i')[1]), 1) - self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) - self.assertEqual(len(xnames[2].lookup('i')[1]), 1) - self.assertEqual(xnames[2].lookup('i')[1][0].lineno, 4) - - def test_list_comp_target(self): - """test the list comprehension target""" - astroid = builder.string_build(""" -ten = [ var for var in range(10) ] -var - """) - var = astroid.body[1].value - if sys.version_info < (3, 0): - self.assertEqual(var.infered(), [YES]) - else: - self.assertRaises(UnresolvableName, var.infered) - - @require_version('2.7') - def test_dict_comps(self): - astroid = builder.string_build(""" -print ({ i: j for i in range(10) for j in range(10) }) -print ({ i: j for i in range(10) for j in range(10) }) - """, __name__, __file__) - xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'i'] - self.assertEqual(len(xnames[0].lookup('i')[1]), 1) - self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) - self.assertEqual(len(xnames[1].lookup('i')[1]), 1) - self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) - - xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'j'] - self.assertEqual(len(xnames[0].lookup('i')[1]), 1) - self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) - self.assertEqual(len(xnames[1].lookup('i')[1]), 1) - self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) - - @require_version('2.7') - def test_set_comps(self): - astroid = builder.string_build(""" -print ({ i for i in range(10) }) -print ({ i for i in range(10) }) - """, __name__, __file__) - xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'i'] - self.assertEqual(len(xnames[0].lookup('i')[1]), 1) - self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2) - self.assertEqual(len(xnames[1].lookup('i')[1]), 1) - self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3) - - @require_version('2.7') - def test_set_comp_closure(self): - astroid = builder.string_build(""" -ten = { var for var in range(10) } -var - """) - var = astroid.body[1].value - self.assertRaises(UnresolvableName, var.infered) - - def test_generator_attributes(self): - tree = builder.string_build(""" -def count(): - "test" - yield 0 - -iterer = count() -num = iterer.next() - """) - next = tree.body[2].value.func # Getattr - gener = next.expr.infered()[0] # Generator - if sys.version_info < (3, 0): - self.assertIsInstance(gener.getattr('next')[0], Function) - else: - self.assertIsInstance(gener.getattr('__next__')[0], Function) - self.assertIsInstance(gener.getattr('send')[0], Function) - self.assertIsInstance(gener.getattr('throw')[0], Function) - self.assertIsInstance(gener.getattr('close')[0], Function) - - def test_explicit___name__(self): - code = ''' -class Pouet: - __name__ = "pouet" -p1 = Pouet() - -class PouetPouet(Pouet): pass -p2 = Pouet() - -class NoName: pass -p3 = NoName() -''' - astroid = builder.string_build(code, __name__, __file__) - p1 = astroid['p1'].infer().next() - self.assertTrue(p1.getattr('__name__')) - p2 = astroid['p2'].infer().next() - self.assertTrue(p2.getattr('__name__')) - self.assertTrue(astroid['NoName'].getattr('__name__')) - p3 = astroid['p3'].infer().next() - self.assertRaises(NotFoundError, p3.getattr, '__name__') - - - def test_function_module_special(self): - astroid = builder.string_build(''' -def initialize(linter): - """initialize linter with checkers in this package """ - package_load(linter, __path__[0]) - ''', 'data.__init__', 'data/__init__.py') - path = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == '__path__'][0] - self.assertEqual(len(path.lookup('__path__')[1]), 1) - - - def test_builtin_lookup(self): - self.assertEqual(builtin_lookup('__dict__')[1], ()) - intstmts = builtin_lookup('int')[1] - self.assertEqual(len(intstmts), 1) - self.assertIsInstance(intstmts[0], nodes.Class) - self.assertEqual(intstmts[0].name, 'int') - self.assertIs(intstmts[0], nodes.const_factory(1)._proxied) - - - def test_decorator_arguments_lookup(self): - code = ''' -def decorator(value): - def wrapper(function): - return function - return wrapper - -class foo: - member = 10 - - @decorator(member) #This will cause pylint to complain - def test(self): - pass - ''' - astroid = builder.string_build(code, __name__, __file__) - member = get_name_node(astroid['foo'], 'member') - it = member.infer() - obj = it.next() - self.assertIsInstance(obj, nodes.Const) - self.assertEqual(obj.value, 10) - self.assertRaises(StopIteration, it.next) - - - def test_inner_decorator_member_lookup(self): - code = ''' -class FileA: - def decorator(bla): - return bla - - @decorator - def funcA(): - return 4 - ''' - astroid = builder.string_build(code, __name__, __file__) - decname = get_name_node(astroid['FileA'], 'decorator') - it = decname.infer() - obj = it.next() - self.assertIsInstance(obj, nodes.Function) - self.assertRaises(StopIteration, it.next) - - - def test_static_method_lookup(self): - code = ''' -class FileA: - @staticmethod - def funcA(): - return 4 - - -class Test: - FileA = [1,2,3] - - def __init__(self): - print (FileA.funcA()) - ''' - astroid = builder.string_build(code, __name__, __file__) - it = astroid['Test']['__init__'].ilookup('FileA') - obj = it.next() - self.assertIsInstance(obj, nodes.Class) - self.assertRaises(StopIteration, it.next) - - - def test_global_delete(self): - code = ''' -def run2(): - f = Frobble() - -class Frobble: - pass -Frobble.mumble = True - -del Frobble - -def run1(): - f = Frobble() -''' - astroid = builder.string_build(code, __name__, __file__) - stmts = astroid['run2'].lookup('Frobbel')[1] - self.assertEqual(len(stmts), 0) - stmts = astroid['run1'].lookup('Frobbel')[1] - self.assertEqual(len(stmts), 0) - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_manager.py astroid-1.3.8/test/unittest_manager.py --- astroid-1.0.1/test/unittest_manager.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_manager.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -from logilab.common.testlib import TestCase, unittest_main - -import sys -from os.path import join, abspath, dirname -from astroid.manager import AstroidManager, _silent_no_wrap -from astroid.bases import BUILTINS - -DATA = join(dirname(abspath(__file__)), 'data') - -class AstroidManagerTC(TestCase): - def setUp(self): - self.manager = AstroidManager() - self.manager.astroid_cache.clear() - - def test_ast_from_module(self): - import unittest - astroid = self.manager.ast_from_module(unittest) - self.assertEqual(astroid.pure_python, True) - import time - astroid = self.manager.ast_from_module(time) - self.assertEqual(astroid.pure_python, False) - - def test_ast_from_class(self): - astroid = self.manager.ast_from_class(int) - self.assertEqual(astroid.name, 'int') - self.assertEqual(astroid.parent.frame().name, BUILTINS) - - astroid = self.manager.ast_from_class(object) - self.assertEqual(astroid.name, 'object') - self.assertEqual(astroid.parent.frame().name, BUILTINS) - self.assertIn('__setattr__', astroid) - - def _test_ast_from_zip(self, archive): - origpath = sys.path[:] - sys.modules.pop('mypypa', None) - archive_path = join(DATA, archive) - sys.path.insert(0, archive_path) - try: - module = self.manager.ast_from_module_name('mypypa') - self.assertEqual(module.name, 'mypypa') - self.assertTrue(module.file.endswith('%s/mypypa' % archive), - module.file) - finally: - # remove the module, else after importing egg, we don't get the zip - if 'mypypa' in self.manager.astroid_cache: - del self.manager.astroid_cache['mypypa'] - del self.manager._mod_file_cache[('mypypa', None)] - if archive_path in sys.path_importer_cache: - del sys.path_importer_cache[archive_path] - sys.path = origpath - - def test_ast_from_module_name_egg(self): - self._test_ast_from_zip('MyPyPa-0.1.0-py2.5.egg') - - def test_ast_from_module_name_zip(self): - self._test_ast_from_zip('MyPyPa-0.1.0-py2.5.zip') - - def test_from_directory(self): - obj = self.manager.project_from_files([DATA], _silent_no_wrap, 'data') - self.assertEqual(obj.name, 'data') - self.assertEqual(obj.path, join(DATA, '__init__.py')) - - def test_project_node(self): - obj = self.manager.project_from_files([DATA], _silent_no_wrap, 'data') - expected = set(['SSL1', '__init__', 'all', 'appl', 'format', 'module', - 'module2', 'noendingnewline', 'nonregr', 'notall']) - expected = ['data', 'data.SSL1', 'data.SSL1.Connection1', - 'data.absimport', 'data.all', - 'data.appl', 'data.appl.myConnection', 'data.email', 'data.format', - 'data.module', 'data.module2', 'data.noendingnewline', - 'data.nonregr', 'data.notall'] - self.assertListEqual(sorted(k for k in obj.keys()), expected) - - def test_do_not_expose_main(self): - obj = self.manager.ast_from_module_name('__main__') - self.assertEqual(obj.name, '__main__') - self.assertEqual(obj.items(), []) - - -class BorgAstroidManagerTC(TestCase): - - def test_borg(self): - """test that the AstroidManager is really a borg, i.e. that two different - instances has same cache""" - first_manager = AstroidManager() - built = first_manager.ast_from_module_name(BUILTINS) - - second_manager = AstroidManager() - second_built = first_manager.ast_from_module_name(BUILTINS) - self.assertIs(built, second_built) - - -if __name__ == '__main__': - unittest_main() - - diff -Nru astroid-1.0.1/test/unittest_nodes.py astroid-1.3.8/test/unittest_nodes.py --- astroid-1.0.1/test/unittest_nodes.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_nodes.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,418 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""tests for specific behaviour of astroid nodes -""" -import sys - -from logilab.common import testlib -from astroid.node_classes import unpack_infer -from astroid.bases import BUILTINS, YES, InferenceContext -from astroid.exceptions import AstroidBuildingException, NotFoundError -from astroid import builder, nodes - -from data import module as test_module - -from os.path import join, abspath, dirname - -DATA = join(dirname(abspath(__file__)), 'data') - -abuilder = builder.AstroidBuilder() - -class AsString(testlib.TestCase): - - def test_varargs_kwargs_as_string(self): - ast = abuilder.string_build( 'raise_string(*args, **kwargs)').body[0] - self.assertEqual(ast.as_string(), 'raise_string(*args, **kwargs)') - - def test_module_as_string(self): - """check as_string on a whole module prepared to be returned identically - """ - data = open(join(DATA, 'module.py')).read() - self.assertMultiLineEqual(MODULE.as_string(), data) - - def test_module2_as_string(self): - """check as_string on a whole module prepared to be returned identically - """ - data = open(join(DATA, 'module2.py')).read() - self.assertMultiLineEqual(MODULE2.as_string(), data) - - @testlib.require_version('2.7') - def test_2_7_as_string(self): - """check as_string for python syntax >= 2.7""" - code = '''one_two = {1, 2} -b = {v: k for (k, v) in enumerate('string')} -cdd = {k for k in b}\n\n''' - ast = abuilder.string_build(code) - self.assertMultiLineEqual(ast.as_string(), code) - - @testlib.require_version('3.0') - def test_3k_as_string(self): - """check as_string for python 3k syntax""" - code = '''print() - -def function(var): - nonlocal counter - try: - hello - except NameError as nexc: - (*hell, o) = b'hello' - raise AttributeError from nexc -\n''' - # TODO : annotations and keywords for class definition are not yet implemented - _todo = ''' -def function(var:int): - nonlocal counter - -class Language(metaclass=Natural): - """natural language""" - ''' - ast = abuilder.string_build(code) - self.assertEqual(ast.as_string(), code) - - -class _NodeTC(testlib.TestCase): - """test transformation of If Node""" - CODE = None - @property - def astroid(self): - try: - return self.__class__.__dict__['CODE_Astroid'] - except KeyError: - astroid = abuilder.string_build(self.CODE) - self.__class__.CODE_Astroid = astroid - return astroid - - -class IfNodeTC(_NodeTC): - """test transformation of If Node""" - CODE = """ -if 0: - print() - -if True: - print() -else: - pass - -if "": - print() -elif []: - raise - -if 1: - print() -elif True: - print() -elif func(): - pass -else: - raise - """ - - def test_if_elif_else_node(self): - """test transformation for If node""" - self.assertEqual(len(self.astroid.body), 4) - for stmt in self.astroid.body: - self.assertIsInstance( stmt, nodes.If) - self.assertFalse(self.astroid.body[0].orelse) # simple If - self.assertIsInstance(self.astroid.body[1].orelse[0], nodes.Pass) # If / else - self.assertIsInstance(self.astroid.body[2].orelse[0], nodes.If) # If / elif - self.assertIsInstance(self.astroid.body[3].orelse[0].orelse[0], nodes.If) - - def test_block_range(self): - # XXX ensure expected values - self.assertEqual(self.astroid.block_range(1), (0, 22)) - self.assertEqual(self.astroid.block_range(10), (0, 22)) # XXX (10, 22) ? - self.assertEqual(self.astroid.body[1].block_range(5), (5, 6)) - self.assertEqual(self.astroid.body[1].block_range(6), (6, 6)) - self.assertEqual(self.astroid.body[1].orelse[0].block_range(7), (7, 8)) - self.assertEqual(self.astroid.body[1].orelse[0].block_range(8), (8, 8)) - - -class TryExceptNodeTC(_NodeTC): - CODE = """ -try: - print ('pouet') -except IOError: - pass -except UnicodeError: - print() -else: - print() - """ - def test_block_range(self): - # XXX ensure expected values - self.assertEqual(self.astroid.body[0].block_range(1), (1, 8)) - self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) - self.assertEqual(self.astroid.body[0].block_range(3), (3, 8)) - self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) - self.assertEqual(self.astroid.body[0].block_range(5), (5, 5)) - self.assertEqual(self.astroid.body[0].block_range(6), (6, 6)) - self.assertEqual(self.astroid.body[0].block_range(7), (7, 7)) - self.assertEqual(self.astroid.body[0].block_range(8), (8, 8)) - - -class TryFinallyNodeTC(_NodeTC): - CODE = """ -try: - print ('pouet') -finally: - print ('pouet') - """ - def test_block_range(self): - # XXX ensure expected values - self.assertEqual(self.astroid.body[0].block_range(1), (1, 4)) - self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) - self.assertEqual(self.astroid.body[0].block_range(3), (3, 4)) - self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) - - -class TryFinally25NodeTC(_NodeTC): - CODE = """ -try: - print('pouet') -except Exception: - print ('oops') -finally: - print ('pouet') - """ - def test_block_range(self): - # XXX ensure expected values - self.assertEqual(self.astroid.body[0].block_range(1), (1, 6)) - self.assertEqual(self.astroid.body[0].block_range(2), (2, 2)) - self.assertEqual(self.astroid.body[0].block_range(3), (3, 4)) - self.assertEqual(self.astroid.body[0].block_range(4), (4, 4)) - self.assertEqual(self.astroid.body[0].block_range(5), (5, 5)) - self.assertEqual(self.astroid.body[0].block_range(6), (6, 6)) - - -class TryExcept2xNodeTC(_NodeTC): - CODE = """ -try: - hello -except AttributeError, (retval, desc): - pass - """ - def test_tuple_attribute(self): - if sys.version_info >= (3, 0): - self.skipTest('syntax removed from py3.x') - handler = self.astroid.body[0].handlers[0] - self.assertIsInstance(handler.name, nodes.Tuple) - - -MODULE = abuilder.module_build(test_module) -MODULE2 = abuilder.file_build(join(DATA, 'module2.py'), 'data.module2') - - -class ImportNodeTC(testlib.TestCase): - - def test_import_self_resolve(self): - myos = MODULE2.igetattr('myos').next() - self.assertTrue(isinstance(myos, nodes.Module), myos) - self.assertEqual(myos.name, 'os') - self.assertEqual(myos.qname(), 'os') - self.assertEqual(myos.pytype(), '%s.module' % BUILTINS) - - def test_from_self_resolve(self): - spawn = MODULE.igetattr('spawn').next() - self.assertTrue(isinstance(spawn, nodes.Class), spawn) - self.assertEqual(spawn.root().name, 'logilab.common.shellutils') - self.assertEqual(spawn.qname(), 'logilab.common.shellutils.Execute') - self.assertEqual(spawn.pytype(), '%s.classobj' % BUILTINS) - abspath = MODULE2.igetattr('abspath').next() - self.assertTrue(isinstance(abspath, nodes.Function), abspath) - self.assertEqual(abspath.root().name, 'os.path') - self.assertEqual(abspath.qname(), 'os.path.abspath') - self.assertEqual(abspath.pytype(), '%s.function' % BUILTINS) - - def test_real_name(self): - from_ = MODULE['spawn'] - self.assertEqual(from_.real_name('spawn'), 'Execute') - imp_ = MODULE['os'] - self.assertEqual(imp_.real_name('os'), 'os') - self.assertRaises(NotFoundError, imp_.real_name, 'os.path') - imp_ = MODULE['spawn'] - self.assertEqual(imp_.real_name('spawn'), 'Execute') - self.assertRaises(NotFoundError, imp_.real_name, 'Execute') - imp_ = MODULE2['YO'] - self.assertEqual(imp_.real_name('YO'), 'YO') - self.assertRaises(NotFoundError, imp_.real_name, 'data') - - def test_as_string(self): - ast = MODULE['modutils'] - self.assertEqual(ast.as_string(), "from logilab.common import modutils") - ast = MODULE['spawn'] - self.assertEqual(ast.as_string(), "from logilab.common.shellutils import Execute as spawn") - ast = MODULE['os'] - self.assertEqual(ast.as_string(), "import os.path") - code = """from . import here -from .. import door -from .store import bread -from ..cave import wine\n\n""" - ast = abuilder.string_build(code) - self.assertMultiLineEqual(ast.as_string(), code) - - def test_bad_import_inference(self): - # Explication of bug - '''When we import PickleError from nonexistent, a call to the infer - method of this From node will be made by unpack_infer. - inference.infer_from will try to import this module, which will fail and - raise a InferenceException (by mixins.do_import_module). The infer_name - will catch this exception and yield and YES instead. - ''' - - code = '''try: - from pickle import PickleError -except ImportError: - from nonexistent import PickleError - -try: - pass -except PickleError: - pass - ''' - - astroid = abuilder.string_build(code) - from_node = astroid.body[1].handlers[0].body[0] - handler_type = astroid.body[1].handlers[0].type - - excs = list(unpack_infer(handler_type)) - - def test_absolute_import(self): - astroid = abuilder.file_build(self.datapath('absimport.py')) - ctx = InferenceContext() - ctx.lookupname = 'message' - # will fail if absolute import failed - astroid['message'].infer(ctx).next() - ctx.lookupname = 'email' - m = astroid['email'].infer(ctx).next() - self.assertFalse(m.file.startswith(self.datapath('email.py'))) - - -class CmpNodeTC(testlib.TestCase): - def test_as_string(self): - ast = abuilder.string_build("a == 2").body[0] - self.assertEqual(ast.as_string(), "a == 2") - - -class ConstNodeTC(testlib.TestCase): - - def _test(self, value): - node = nodes.const_factory(value) - self.assertIsInstance(node._proxied, nodes.Class) - self.assertEqual(node._proxied.name, value.__class__.__name__) - self.assertIs(node.value, value) - self.assertTrue(node._proxied.parent) - self.assertEqual(node._proxied.root().name, value.__class__.__module__) - - def test_none(self): - self._test(None) - - def test_bool(self): - self._test(True) - - def test_int(self): - self._test(1) - - def test_float(self): - self._test(1.0) - - def test_complex(self): - self._test(1.0j) - - def test_str(self): - self._test('a') - - def test_unicode(self): - self._test(u'a') - - -class NameNodeTC(testlib.TestCase): - def test_assign_to_True(self): - """test that True and False assignements don't crash""" - code = """True = False -def hello(False): - pass -del True - """ - if sys.version_info >= (3, 0): - self.assertRaises(SyntaxError,#might become AstroidBuildingException - abuilder.string_build, code) - else: - ast = abuilder.string_build(code) - ass_true = ast['True'] - self.assertIsInstance(ass_true, nodes.AssName) - self.assertEqual(ass_true.name, "True") - del_true = ast.body[2].targets[0] - self.assertIsInstance(del_true, nodes.DelName) - self.assertEqual(del_true.name, "True") - - -class ArgumentsNodeTC(testlib.TestCase): - def test_linenumbering(self): - ast = abuilder.string_build(''' -def func(a, - b): pass -x = lambda x: None - ''') - self.assertEqual(ast['func'].args.fromlineno, 2) - self.assertFalse(ast['func'].args.is_statement) - xlambda = ast['x'].infer().next() - self.assertEqual(xlambda.args.fromlineno, 4) - self.assertEqual(xlambda.args.tolineno, 4) - self.assertFalse(xlambda.args.is_statement) - if sys.version_info < (3, 0): - self.assertEqual(ast['func'].args.tolineno, 3) - else: - self.skipTest('FIXME http://bugs.python.org/issue10445 ' - '(no line number on function args)') - - -class SliceNodeTC(testlib.TestCase): - def test(self): - for code in ('a[0]', 'a[1:3]', 'a[:-1:step]', 'a[:,newaxis]', - 'a[newaxis,:]', 'del L[::2]', 'del A[1]', 'del Br[:]'): - ast = abuilder.string_build(code).body[0] - self.assertEqual(ast.as_string(), code) - - def test_slice_and_subscripts(self): - code = """a[:1] = bord[2:] -a[:1] = bord[2:] -del bree[3:d] -bord[2:] -del av[d::f], a[df:] -a[:1] = bord[2:] -del SRC[::1,newaxis,1:] -tous[vals] = 1010 -del thousand[key] -del a[::2], a[:-1:step] -del Fee.form[left:] -aout.vals = miles.of_stuff -del (ccok, (name.thing, foo.attrib.value)), Fee.form[left:] -if all[1] == bord[0:]: - pass\n\n""" - ast = abuilder.string_build(code) - self.assertEqual(ast.as_string(), code) - -class EllipsisNodeTC(testlib.TestCase): - def test(self): - ast = abuilder.string_build('a[...]').body[0] - self.assertEqual(ast.as_string(), 'a[...]') - -if __name__ == '__main__': - testlib.unittest_main() diff -Nru astroid-1.0.1/test/unittest_python3.py astroid-1.3.8/test/unittest_python3.py --- astroid-1.0.1/test/unittest_python3.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_python3.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -import sys - -from logilab.common.testlib import TestCase, unittest_main, require_version - -from astroid.node_classes import Assign -from astroid.manager import AstroidManager -from astroid.builder import AstroidBuilder - - -class Python3TC(TestCase): - def setUp(self): - self.manager = AstroidManager() - self.builder = AstroidBuilder(self.manager) - self.manager.astroid_cache.clear() - - @require_version('3.0') - def test_starred_notation(self): - astroid = self.builder.string_build("*a, b = [1, 2, 3]", 'test', 'test') - - # Get the star node - node = next(next(next(astroid.get_children()).get_children()).get_children()) - - self.assertTrue(isinstance(node.ass_type(), Assign)) - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_regrtest.py astroid-1.3.8/test/unittest_regrtest.py --- astroid-1.0.1/test/unittest_regrtest.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_regrtest.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . - -from logilab.common.testlib import unittest_main, TestCase - -from astroid import ResolveError, MANAGER, Instance, nodes, YES, InferenceError -from astroid.builder import AstroidBuilder -from astroid.raw_building import build_module -from astroid.manager import AstroidManager - -import sys -from os.path import join, abspath, dirname - -class NonRegressionTC(TestCase): - - def setUp(self): - sys.path.insert(0, join(dirname(abspath(__file__)), 'regrtest_data')) - - def tearDown(self): - sys.path.pop(0) - - def brainless_manager(self): - manager = AstroidManager() - # avoid caching into the AstroidManager borg since we get problems - # with other tests : - manager.__dict__ = {} - manager.astroid_cache = {} - manager._mod_file_cache = {} - manager.transforms = {} - return manager - - def test_module_path(self): - man = self.brainless_manager() - mod = man.ast_from_module_name('package.import_package_subpackage_module') - package = mod.igetattr('package').next() - self.assertEqual(package.name, 'package') - subpackage = package.igetattr('subpackage').next() - self.assertIsInstance(subpackage, nodes.Module) - self.assertTrue(subpackage.package) - self.assertEqual(subpackage.name, 'package.subpackage') - module = subpackage.igetattr('module').next() - self.assertEqual(module.name, 'package.subpackage.module') - - - def test_package_sidepackage(self): - manager = self.brainless_manager() - assert 'package.sidepackage' not in MANAGER.astroid_cache - package = manager.ast_from_module_name('absimp') - self.assertIsInstance(package, nodes.Module) - self.assertTrue(package.package) - subpackage = package.getattr('sidepackage')[0].infer().next() - self.assertIsInstance(subpackage, nodes.Module) - self.assertTrue(subpackage.package) - self.assertEqual(subpackage.name, 'absimp.sidepackage') - - - def test_living_property(self): - builder = AstroidBuilder() - builder._done = {} - builder._module = sys.modules[__name__] - builder.object_build(build_module('module_name', ''), Whatever) - - - def test_new_style_class_detection(self): - try: - import pygtk - except ImportError: - self.skipTest('test skipped: pygtk is not available') - # XXX may fail on some pygtk version, because objects in - # gobject._gobject have __module__ set to gobject :( - builder = AstroidBuilder() - data = """ -import pygtk -pygtk.require("2.6") -import gobject - -class A(gobject.GObject): - pass -""" - astroid = builder.string_build(data, __name__, __file__) - a = astroid['A'] - self.assertTrue(a.newstyle) - - - def test_pylint_config_attr(self): - try: - from pylint import lint - except ImportError: - self.skipTest('pylint not available') - mod = MANAGER.ast_from_module_name('pylint.lint') - pylinter = mod['PyLinter'] - expect = ['OptionsManagerMixIn', 'object', 'MessagesHandlerMixIn', - 'ReportsHandlerMixIn', 'BaseTokenChecker', 'BaseChecker', - 'OptionsProviderMixIn', 'ASTWalker'] - self.assertListEqual([c.name for c in pylinter.ancestors()], - expect) - self.assertTrue(list(Instance(pylinter).getattr('config'))) - infered = list(Instance(pylinter).igetattr('config')) - self.assertEqual(len(infered), 1) - self.assertEqual(infered[0].root().name, 'optparse') - self.assertEqual(infered[0].name, 'Values') - - def test_numpy_crash(self): - """test don't crash on numpy""" - #a crash occured somewhere in the past, and an - # InferenceError instead of a crash was better, but now we even infer! - try: - import numpy - except ImportError: - self.skipTest('test skipped: numpy is not available') - builder = AstroidBuilder() - data = """ -from numpy import multiply - -multiply(1, 2, 3) -""" - astroid = builder.string_build(data, __name__, __file__) - callfunc = astroid.body[1].value.func - infered = callfunc.infered() - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], Instance) - - -class Whatever(object): - a = property(lambda x: x, lambda x: x) - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_scoped_nodes.py astroid-1.3.8/test/unittest_scoped_nodes.py --- astroid-1.0.1/test/unittest_scoped_nodes.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_scoped_nodes.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,669 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""tests for specific behaviour of astroid scoped nodes (i.e. module, class and -function) -""" - -import sys -from os.path import join, abspath, dirname - -from logilab.common.testlib import TestCase, unittest_main - -from astroid import builder, nodes, scoped_nodes, \ - InferenceError, NotFoundError, NoDefault -from astroid.bases import BUILTINS, Instance, BoundMethod, UnboundMethod -from astroid.test_utils import extract_node - -abuilder = builder.AstroidBuilder() -DATA = join(dirname(abspath(__file__)), 'data') -REGRTEST_DATA = join(dirname(abspath(__file__)), 'regrtest_data') -MODULE = abuilder.file_build(join(DATA, 'module.py'), 'data.module') -MODULE2 = abuilder.file_build(join(DATA, 'module2.py'), 'data.module2') -NONREGR = abuilder.file_build(join(DATA, 'nonregr.py'), 'data.nonregr') - -PACK = abuilder.file_build(join(DATA, '__init__.py'), 'data') - -def _test_dict_interface(self, node, test_attr): - self.assertIs(node[test_attr], node[test_attr]) - self.assertIn(test_attr, node) - node.keys() - node.values() - node.items() - iter(node) - - -class ModuleNodeTC(TestCase): - - def test_special_attributes(self): - self.assertEqual(len(MODULE.getattr('__name__')), 1) - self.assertIsInstance(MODULE.getattr('__name__')[0], nodes.Const) - self.assertEqual(MODULE.getattr('__name__')[0].value, 'data.module') - self.assertEqual(len(MODULE.getattr('__doc__')), 1) - self.assertIsInstance(MODULE.getattr('__doc__')[0], nodes.Const) - self.assertEqual(MODULE.getattr('__doc__')[0].value, 'test module for astroid\n') - self.assertEqual(len(MODULE.getattr('__file__')), 1) - self.assertIsInstance(MODULE.getattr('__file__')[0], nodes.Const) - self.assertEqual(MODULE.getattr('__file__')[0].value, join(DATA, 'module.py')) - self.assertEqual(len(MODULE.getattr('__dict__')), 1) - self.assertIsInstance(MODULE.getattr('__dict__')[0], nodes.Dict) - self.assertRaises(NotFoundError, MODULE.getattr, '__path__') - self.assertEqual(len(PACK.getattr('__path__')), 1) - self.assertIsInstance(PACK.getattr('__path__')[0], nodes.List) - - def test_dict_interface(self): - _test_dict_interface(self, MODULE, 'YO') - - def test_getattr(self): - yo = MODULE.getattr('YO')[0] - self.assertIsInstance(yo, nodes.Class) - self.assertEqual(yo.name, 'YO') - red = MODULE.igetattr('redirect').next() - self.assertIsInstance(red, nodes.Function) - self.assertEqual(red.name, 'four_args') - spawn = MODULE.igetattr('spawn').next() - self.assertIsInstance(spawn, nodes.Class) - self.assertEqual(spawn.name, 'Execute') - # resolve packageredirection - sys.path.insert(1, DATA) - mod = abuilder.file_build(join(DATA, 'appl/myConnection.py'), - 'appl.myConnection') - try: - ssl = mod.igetattr('SSL1').next() - cnx = ssl.igetattr('Connection').next() - self.assertEqual(cnx.__class__, nodes.Class) - self.assertEqual(cnx.name, 'Connection') - self.assertEqual(cnx.root().name, 'SSL1.Connection1') - finally: - del sys.path[1] - self.assertEqual(len(NONREGR.getattr('enumerate')), 2) - # raise ResolveError - self.assertRaises(InferenceError, MODULE.igetattr, 'YOAA') - - def test_wildard_import_names(self): - m = abuilder.file_build(join(DATA, 'all.py'), 'all') - self.assertEqual(m.wildcard_import_names(), ['Aaa', '_bla', 'name']) - m = abuilder.file_build(join(DATA, 'notall.py'), 'notall') - res = sorted(m.wildcard_import_names()) - self.assertEqual(res, ['Aaa', 'func', 'name', 'other']) - - def test_module_getattr(self): - data = ''' -appli = application -appli += 2 -del appli - ''' - astroid = abuilder.string_build(data, __name__, __file__) - # test del statement not returned by getattr - self.assertEqual(len(astroid.getattr('appli')), 2, - astroid.getattr('appli')) - - def test_relative_to_absolute_name(self): - # package - mod = nodes.Module('very.multi.package', 'doc') - mod.package = True - modname = mod.relative_to_absolute_name('utils', 1) - self.assertEqual(modname, 'very.multi.package.utils') - modname = mod.relative_to_absolute_name('utils', 2) - self.assertEqual(modname, 'very.multi.utils') - modname = mod.relative_to_absolute_name('utils', 0) - self.assertEqual(modname, 'very.multi.package.utils') - modname = mod.relative_to_absolute_name('', 1) - self.assertEqual(modname, 'very.multi.package') - # non package - mod = nodes.Module('very.multi.module', 'doc') - mod.package = False - modname = mod.relative_to_absolute_name('utils', 0) - self.assertEqual(modname, 'very.multi.utils') - modname = mod.relative_to_absolute_name('utils', 1) - self.assertEqual(modname, 'very.multi.utils') - modname = mod.relative_to_absolute_name('utils', 2) - self.assertEqual(modname, 'very.utils') - modname = mod.relative_to_absolute_name('', 1) - self.assertEqual(modname, 'very.multi') - - def test_import_1(self): - data = '''from . import subpackage''' - astroid = abuilder.string_build(data, 'package', join(REGRTEST_DATA, 'package', '__init__.py')) - sys.path.insert(1, REGRTEST_DATA) - try: - m = astroid.import_module('', level=1) - self.assertEqual(m.name, 'package') - infered = list(astroid.igetattr('subpackage')) - self.assertEqual(len(infered), 1) - self.assertEqual(infered[0].name, 'package.subpackage') - finally: - del sys.path[1] - - - def test_import_2(self): - data = '''from . import subpackage as pouet''' - astroid = abuilder.string_build(data, 'package', join(dirname(abspath(__file__)), 'regrtest_data', 'package', '__init__.py')) - sys.path.insert(1, REGRTEST_DATA) - try: - m = astroid.import_module('', level=1) - self.assertEqual(m.name, 'package') - infered = list(astroid.igetattr('pouet')) - self.assertEqual(len(infered), 1) - self.assertEqual(infered[0].name, 'package.subpackage') - finally: - del sys.path[1] - - -class FunctionNodeTC(TestCase): - - def test_special_attributes(self): - func = MODULE2['make_class'] - self.assertEqual(len(func.getattr('__name__')), 1) - self.assertIsInstance(func.getattr('__name__')[0], nodes.Const) - self.assertEqual(func.getattr('__name__')[0].value, 'make_class') - self.assertEqual(len(func.getattr('__doc__')), 1) - self.assertIsInstance(func.getattr('__doc__')[0], nodes.Const) - self.assertEqual(func.getattr('__doc__')[0].value, 'check base is correctly resolved to Concrete0') - self.assertEqual(len(MODULE.getattr('__dict__')), 1) - self.assertIsInstance(MODULE.getattr('__dict__')[0], nodes.Dict) - - def test_dict_interface(self): - _test_dict_interface(self, MODULE['global_access'], 'local') - - def test_default_value(self): - func = MODULE2['make_class'] - self.assertIsInstance(func.args.default_value('base'), nodes.Getattr) - self.assertRaises(NoDefault, func.args.default_value, 'args') - self.assertRaises(NoDefault, func.args.default_value, 'kwargs') - self.assertRaises(NoDefault, func.args.default_value, 'any') - #self.assertIsInstance(func.mularg_class('args'), nodes.Tuple) - #self.assertIsInstance(func.mularg_class('kwargs'), nodes.Dict) - #self.assertIsNone(func.mularg_class('base')) - - def test_navigation(self): - function = MODULE['global_access'] - self.assertEqual(function.statement(), function) - l_sibling = function.previous_sibling() - # check taking parent if child is not a stmt - self.assertIsInstance(l_sibling, nodes.Assign) - child = function.args.args[0] - self.assertIs(l_sibling, child.previous_sibling()) - r_sibling = function.next_sibling() - self.assertIsInstance(r_sibling, nodes.Class) - self.assertEqual(r_sibling.name, 'YO') - self.assertIs(r_sibling, child.next_sibling()) - last = r_sibling.next_sibling().next_sibling().next_sibling() - self.assertIsInstance(last, nodes.Assign) - self.assertIsNone(last.next_sibling()) - first = l_sibling.previous_sibling().previous_sibling().previous_sibling().previous_sibling().previous_sibling() - self.assertIsNone(first.previous_sibling()) - - def test_nested_args(self): - if sys.version_info >= (3, 0): - self.skipTest("nested args has been removed in py3.x") - code = ''' -def nested_args(a, (b, c, d)): - "nested arguments test" - ''' - tree = abuilder.string_build(code) - func = tree['nested_args'] - self.assertEqual(sorted(func.locals), ['a', 'b', 'c', 'd']) - self.assertEqual(func.args.format_args(), 'a, (b, c, d)') - - def test_four_args(self): - func = MODULE['four_args'] - #self.assertEqual(func.args.args, ['a', ('b', 'c', 'd')]) - local = sorted(func.keys()) - self.assertEqual(local, ['a', 'b', 'c', 'd']) - self.assertEqual(func.type, 'function') - - def test_format_args(self): - func = MODULE2['make_class'] - self.assertEqual(func.args.format_args(), 'any, base=data.module.YO, *args, **kwargs') - func = MODULE['four_args'] - self.assertEqual(func.args.format_args(), 'a, b, c, d') - - def test_is_generator(self): - self.assertTrue(MODULE2['generator'].is_generator()) - self.assertFalse(MODULE2['not_a_generator'].is_generator()) - self.assertFalse(MODULE2['make_class'].is_generator()) - - def test_is_abstract(self): - method = MODULE2['AbstractClass']['to_override'] - self.assertTrue(method.is_abstract(pass_is_abstract=False)) - self.assertEqual(method.qname(), 'data.module2.AbstractClass.to_override') - self.assertEqual(method.pytype(), '%s.instancemethod' % BUILTINS) - method = MODULE2['AbstractClass']['return_something'] - self.assertFalse(method.is_abstract(pass_is_abstract=False)) - # non regression : test raise "string" doesn't cause an exception in is_abstract - func = MODULE2['raise_string'] - self.assertFalse(func.is_abstract(pass_is_abstract=False)) - - def test_is_abstract_decorated(self): - methods = extract_node(""" - import abc - - class Klass(object): - @abc.abstractproperty - def prop(self): #@ - pass - - @abc.abstractmethod - def method1(self): #@ - pass - - some_other_decorator = lambda x: x - @some_other_decorator - def method2(self): #@ - pass - - """) - self.assertTrue(methods[0].is_abstract(pass_is_abstract=False)) - self.assertTrue(methods[1].is_abstract(pass_is_abstract=False)) - self.assertFalse(methods[2].is_abstract(pass_is_abstract=False)) - -## def test_raises(self): -## method = MODULE2['AbstractClass']['to_override'] -## self.assertEqual([str(term) for term in method.raises()], -## ["CallFunc(Name('NotImplementedError'), [], None, None)"] ) - -## def test_returns(self): -## method = MODULE2['AbstractClass']['return_something'] -## # use string comp since Node doesn't handle __cmp__ -## self.assertEqual([str(term) for term in method.returns()], -## ["Const('toto')", "Const(None)"]) - - def test_lambda_pytype(self): - data = ''' -def f(): - g = lambda: None - ''' - astroid = abuilder.string_build(data, __name__, __file__) - g = list(astroid['f'].ilookup('g'))[0] - self.assertEqual(g.pytype(), '%s.function' % BUILTINS) - - def test_lambda_qname(self): - astroid = abuilder.string_build(''' -lmbd = lambda: None -''', __name__, __file__) - self.assertEqual('%s.' % __name__, astroid['lmbd'].parent.value.qname()) - - def test_is_method(self): - data = ''' -class A: - def meth1(self): - return 1 - @classmethod - def meth2(cls): - return 2 - @staticmethod - def meth3(): - return 3 - -def function(): - return 0 - -@staticmethod -def sfunction(): - return -1 - ''' - astroid = abuilder.string_build(data, __name__, __file__) - self.assertTrue(astroid['A']['meth1'].is_method()) - self.assertTrue(astroid['A']['meth2'].is_method()) - self.assertTrue(astroid['A']['meth3'].is_method()) - self.assertFalse(astroid['function'].is_method()) - self.assertFalse(astroid['sfunction'].is_method()) - - def test_argnames(self): - if sys.version_info < (3, 0): - code = 'def f(a, (b, c), *args, **kwargs): pass' - else: - code = 'def f(a, b, c, *args, **kwargs): pass' - astroid = abuilder.string_build(code, __name__, __file__) - self.assertEqual(astroid['f'].argnames(), ['a', 'b', 'c', 'args', 'kwargs']) - - def test_return_nothing(self): - """test infered value on a function with empty return""" - data = ''' -def func(): - return - -a = func() -''' - astroid = abuilder.string_build(data, __name__, __file__) - call = astroid.body[1].value - func_vals = call.infered() - self.assertEqual(len(func_vals), 1) - self.assertIsInstance(func_vals[0], nodes.Const) - self.assertIsNone(func_vals[0].value) - - def test_func_instance_attr(self): - """test instance attributes for functions""" - data= """ -def test(): - print(test.bar) - -test.bar = 1 -test() - """ - astroid = abuilder.string_build(data, 'mod', __file__) - func = astroid.body[2].value.func.infered()[0] - self.assertIsInstance(func, nodes.Function) - self.assertEqual(func.name, 'test') - one = func.getattr('bar')[0].infered()[0] - self.assertIsInstance(one, nodes.Const) - self.assertEqual(one.value, 1) - - -class ClassNodeTC(TestCase): - - def test_dict_interface(self): - _test_dict_interface(self, MODULE['YOUPI'], 'method') - - def test_cls_special_attributes_1(self): - cls = MODULE['YO'] - self.assertEqual(len(cls.getattr('__bases__')), 1) - self.assertEqual(len(cls.getattr('__name__')), 1) - self.assertIsInstance(cls.getattr('__name__')[0], nodes.Const) - self.assertEqual(cls.getattr('__name__')[0].value, 'YO') - self.assertEqual(len(cls.getattr('__doc__')), 1) - self.assertIsInstance(cls.getattr('__doc__')[0], nodes.Const) - self.assertEqual(cls.getattr('__doc__')[0].value, 'hehe') - self.assertEqual(len(cls.getattr('__module__')), 1) - self.assertIsInstance(cls.getattr('__module__')[0], nodes.Const) - self.assertEqual(cls.getattr('__module__')[0].value, 'data.module') - self.assertEqual(len(cls.getattr('__dict__')), 1) - self.assertRaises(NotFoundError, cls.getattr, '__mro__') - for cls in (nodes.List._proxied, nodes.Const(1)._proxied): - self.assertEqual(len(cls.getattr('__bases__')), 1) - self.assertEqual(len(cls.getattr('__name__')), 1) - self.assertEqual(len(cls.getattr('__doc__')), 1, (cls, cls.getattr('__doc__'))) - self.assertEqual(cls.getattr('__doc__')[0].value, cls.doc) - self.assertEqual(len(cls.getattr('__module__')), 1) - self.assertEqual(len(cls.getattr('__dict__')), 1) - self.assertEqual(len(cls.getattr('__mro__')), 1) - - def test_cls_special_attributes_2(self): - astroid = abuilder.string_build(''' -class A: pass -class B: pass - -A.__bases__ += (B,) -''', __name__, __file__) - self.assertEqual(len(astroid['A'].getattr('__bases__')), 2) - self.assertIsInstance(astroid['A'].getattr('__bases__')[0], nodes.Tuple) - self.assertIsInstance(astroid['A'].getattr('__bases__')[1], nodes.AssAttr) - - def test_instance_special_attributes(self): - for inst in (Instance(MODULE['YO']), nodes.List(), nodes.Const(1)): - self.assertRaises(NotFoundError, inst.getattr, '__mro__') - self.assertRaises(NotFoundError, inst.getattr, '__bases__') - self.assertRaises(NotFoundError, inst.getattr, '__name__') - self.assertEqual(len(inst.getattr('__dict__')), 1) - self.assertEqual(len(inst.getattr('__doc__')), 1) - - def test_navigation(self): - klass = MODULE['YO'] - self.assertEqual(klass.statement(), klass) - l_sibling = klass.previous_sibling() - self.assertTrue(isinstance(l_sibling, nodes.Function), l_sibling) - self.assertEqual(l_sibling.name, 'global_access') - r_sibling = klass.next_sibling() - self.assertIsInstance(r_sibling, nodes.Class) - self.assertEqual(r_sibling.name, 'YOUPI') - - def test_local_attr_ancestors(self): - klass2 = MODULE['YOUPI'] - it = klass2.local_attr_ancestors('__init__') - anc_klass = it.next() - self.assertIsInstance(anc_klass, nodes.Class) - self.assertEqual(anc_klass.name, 'YO') - self.assertRaises(StopIteration, it.next) - it = klass2.local_attr_ancestors('method') - self.assertRaises(StopIteration, it.next) - - def test_instance_attr_ancestors(self): - klass2 = MODULE['YOUPI'] - it = klass2.instance_attr_ancestors('yo') - anc_klass = it.next() - self.assertIsInstance(anc_klass, nodes.Class) - self.assertEqual(anc_klass.name, 'YO') - self.assertRaises(StopIteration, it.next) - klass2 = MODULE['YOUPI'] - it = klass2.instance_attr_ancestors('member') - self.assertRaises(StopIteration, it.next) - - def test_methods(self): - klass2 = MODULE['YOUPI'] - methods = sorted([m.name for m in klass2.methods()]) - self.assertEqual(methods, ['__init__', 'class_method', - 'method', 'static_method']) - methods = [m.name for m in klass2.mymethods()] - methods.sort() - self.assertEqual(methods, ['__init__', 'class_method', - 'method', 'static_method']) - klass2 = MODULE2['Specialization'] - methods = [m.name for m in klass2.mymethods()] - methods.sort() - self.assertEqual(methods, []) - method_locals = klass2.local_attr('method') - self.assertEqual(len(method_locals), 1) - self.assertEqual(method_locals[0].name, 'method') - self.assertRaises(NotFoundError, klass2.local_attr, 'nonexistant') - methods = [m.name for m in klass2.methods()] - methods.sort() - self.assertEqual(methods, ['__init__', 'class_method', - 'method', 'static_method']) - - #def test_rhs(self): - # my_dict = MODULE['MY_DICT'] - # self.assertIsInstance(my_dict.rhs(), nodes.Dict) - # a = MODULE['YO']['a'] - # value = a.rhs() - # self.assertIsInstance(value, nodes.Const) - # self.assertEqual(value.value, 1) - - def test_ancestors(self): - klass = MODULE['YOUPI'] - ancs = [a.name for a in klass.ancestors()] - self.assertEqual(ancs, ['YO']) - klass = MODULE2['Specialization'] - ancs = [a.name for a in klass.ancestors()] - self.assertEqual(ancs, ['YOUPI', 'YO']) - - def test_type(self): - klass = MODULE['YOUPI'] - self.assertEqual(klass.type, 'class') - klass = MODULE2['Metaclass'] - self.assertEqual(klass.type, 'metaclass') - klass = MODULE2['MyException'] - self.assertEqual(klass.type, 'exception') - klass = MODULE2['MyIFace'] - self.assertEqual(klass.type, 'interface') - klass = MODULE2['MyError'] - self.assertEqual(klass.type, 'exception') - - def test_interfaces(self): - for klass, interfaces in (('Concrete0', ['MyIFace']), - ('Concrete1', ['MyIFace', 'AnotherIFace']), - ('Concrete2', ['MyIFace', 'AnotherIFace']), - ('Concrete23', ['MyIFace', 'AnotherIFace'])): - klass = MODULE2[klass] - self.assertEqual([i.name for i in klass.interfaces()], - interfaces) - - def test_concat_interfaces(self): - astroid = abuilder.string_build(''' -class IMachin: pass - -class Correct2: - """docstring""" - __implements__ = (IMachin,) - -class BadArgument: - """docstring""" - __implements__ = (IMachin,) - -class InterfaceCanNowBeFound: - """docstring""" - __implements__ = BadArgument.__implements__ + Correct2.__implements__ - - ''') - self.assertEqual([i.name for i in astroid['InterfaceCanNowBeFound'].interfaces()], - ['IMachin']) - - def test_inner_classes(self): - eee = NONREGR['Ccc']['Eee'] - self.assertEqual([n.name for n in eee.ancestors()], ['Ddd', 'Aaa', 'object']) - - - def test_classmethod_attributes(self): - data = ''' -class WebAppObject(object): - def registered(cls, application): - cls.appli = application - cls.schema = application.schema - cls.config = application.config - return cls - registered = classmethod(registered) - ''' - astroid = abuilder.string_build(data, __name__, __file__) - cls = astroid['WebAppObject'] - self.assertEqual(sorted(cls.locals.keys()), - ['appli', 'config', 'registered', 'schema']) - - - def test_class_getattr(self): - data = ''' -class WebAppObject(object): - appli = application - appli += 2 - del self.appli - ''' - astroid = abuilder.string_build(data, __name__, __file__) - cls = astroid['WebAppObject'] - # test del statement not returned by getattr - self.assertEqual(len(cls.getattr('appli')), 2) - - - def test_instance_getattr(self): - data = ''' -class WebAppObject(object): - def __init__(self, application): - self.appli = application - self.appli += 2 - del self.appli - ''' - astroid = abuilder.string_build(data, __name__, __file__) - inst = Instance(astroid['WebAppObject']) - # test del statement not returned by getattr - self.assertEqual(len(inst.getattr('appli')), 2) - - - def test_instance_getattr_with_class_attr(self): - data = ''' -class Parent: - aa = 1 - cc = 1 - -class Klass(Parent): - aa = 0 - bb = 0 - - def incr(self, val): - self.cc = self.aa - if val > self.aa: - val = self.aa - if val < self.bb: - val = self.bb - self.aa += val - ''' - astroid = abuilder.string_build(data, __name__, __file__) - inst = Instance(astroid['Klass']) - self.assertEqual(len(inst.getattr('aa')), 3, inst.getattr('aa')) - self.assertEqual(len(inst.getattr('bb')), 1, inst.getattr('bb')) - self.assertEqual(len(inst.getattr('cc')), 2, inst.getattr('cc')) - - - def test_getattr_method_transform(self): - data = ''' -class Clazz(object): - - def m1(self, value): - self.value = value - m2 = m1 - -def func(arg1, arg2): - "function that will be used as a method" - return arg1.value + arg2 - -Clazz.m3 = func -inst = Clazz() -inst.m4 = func - ''' - astroid = abuilder.string_build(data, __name__, __file__) - cls = astroid['Clazz'] - # test del statement not returned by getattr - for method in ('m1', 'm2', 'm3'): - inferred = list(cls.igetattr(method)) - self.assertEqual(len(inferred), 1) - self.assertIsInstance(inferred[0], UnboundMethod) - inferred = list(Instance(cls).igetattr(method)) - self.assertEqual(len(inferred), 1) - self.assertIsInstance(inferred[0], BoundMethod) - inferred = list(Instance(cls).igetattr('m4')) - self.assertEqual(len(inferred), 1) - self.assertIsInstance(inferred[0], nodes.Function) - - def test_getattr_from_grandpa(self): - data = ''' -class Future: - attr = 1 - -class Present(Future): - pass - -class Past(Present): - pass -''' - astroid = abuilder.string_build(data) - past = astroid['Past'] - attr = past.getattr('attr') - self.assertEqual(len(attr), 1) - attr1 = attr[0] - self.assertIsInstance(attr1, nodes.AssName) - self.assertEqual(attr1.name, 'attr') - - def test_function_with_decorator_lineno(self): - data = ''' -@f(a=2, - b=3) -def g1(x): - print(x) - -@f(a=2, - b=3) -def g2(): - pass -''' - astroid = abuilder.string_build(data) - self.assertEqual(astroid['g1'].fromlineno, 4) - self.assertEqual(astroid['g1'].tolineno, 5) - self.assertEqual(astroid['g2'].fromlineno, 9) - self.assertEqual(astroid['g2'].tolineno, 10) - - -__all__ = ('ModuleNodeTC', 'ImportNodeTC', 'FunctionNodeTC', 'ClassNodeTC') - -if __name__ == '__main__': - unittest_main() diff -Nru astroid-1.0.1/test/unittest_utils.py astroid-1.3.8/test/unittest_utils.py --- astroid-1.0.1/test/unittest_utils.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test/unittest_utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -from logilab.common.testlib import TestCase, unittest_main - -from astroid import builder, nodes -from astroid.node_classes import are_exclusive - -builder = builder.AstroidBuilder() - -class AreExclusiveTC(TestCase): - def test_not_exclusive(self): - astroid = builder.string_build(""" -x = 10 -for x in range(5): - print (x) - -if x > 0: - print ('#' * x) - """, __name__, __file__) - xass1 = astroid.locals['x'][0] - assert xass1.lineno == 2 - xnames = [n for n in astroid.nodes_of_class(nodes.Name) if n.name == 'x'] - assert len(xnames) == 3 - assert xnames[1].lineno == 6 - self.assertEqual(are_exclusive(xass1, xnames[1]), False) - self.assertEqual(are_exclusive(xass1, xnames[2]), False) - - def test_if(self): - astroid = builder.string_build(''' - -if 1: - a = 1 - a = 2 -elif 2: - a = 12 - a = 13 -else: - a = 3 - a = 4 - ''') - a1 = astroid.locals['a'][0] - a2 = astroid.locals['a'][1] - a3 = astroid.locals['a'][2] - a4 = astroid.locals['a'][3] - a5 = astroid.locals['a'][4] - a6 = astroid.locals['a'][5] - self.assertEqual(are_exclusive(a1, a2), False) - self.assertEqual(are_exclusive(a1, a3), True) - self.assertEqual(are_exclusive(a1, a5), True) - self.assertEqual(are_exclusive(a3, a5), True) - self.assertEqual(are_exclusive(a3, a4), False) - self.assertEqual(are_exclusive(a5, a6), False) - - def test_try_except(self): - astroid = builder.string_build(''' -try: - def exclusive_func2(): - "docstring" -except TypeError: - def exclusive_func2(): - "docstring" -except: - def exclusive_func2(): - "docstring" -else: - def exclusive_func2(): - "this one redefine the one defined line 42" - - ''') - f1 = astroid.locals['exclusive_func2'][0] - f2 = astroid.locals['exclusive_func2'][1] - f3 = astroid.locals['exclusive_func2'][2] - f4 = astroid.locals['exclusive_func2'][3] - self.assertEqual(are_exclusive(f1, f2), True) - self.assertEqual(are_exclusive(f1, f3), True) - self.assertEqual(are_exclusive(f1, f4), False) - self.assertEqual(are_exclusive(f2, f4), True) - self.assertEqual(are_exclusive(f3, f4), True) - self.assertEqual(are_exclusive(f3, f2), True) - - self.assertEqual(are_exclusive(f2, f1), True) - self.assertEqual(are_exclusive(f4, f1), False) - self.assertEqual(are_exclusive(f4, f2), True) - -if __name__ == '__main__': - unittest_main() - diff -Nru astroid-1.0.1/test_utils.py astroid-1.3.8/test_utils.py --- astroid-1.0.1/test_utils.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/test_utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,183 +0,0 @@ -"""Utility functions for test code that uses astroid ASTs as input.""" -import textwrap - -from astroid import nodes -from astroid import builder - -# The name of the transient function that is used to -# wrap expressions to be extracted when calling -# extract_node. -_TRANSIENT_FUNCTION = '__' - -# The comment used to select a statement to be extracted -# when calling extract_node. -_STATEMENT_SELECTOR = '#@' - - -def _extract_expressions(node): - """Find expressions in a call to _TRANSIENT_FUNCTION and extract them. - - The function walks the AST recursively to search for expressions that - are wrapped into a call to _TRANSIENT_FUNCTION. If it finds such an - expression, it completely removes the function call node from the tree, - replacing it by the wrapped expression inside the parent. - - :param node: An astroid node. - :type node: astroid.bases.NodeNG - :yields: The sequence of wrapped expressions on the modified tree - expression can be found. - """ - if (isinstance(node, nodes.CallFunc) - and isinstance(node.func, nodes.Name) - and node.func.name == _TRANSIENT_FUNCTION): - real_expr = node.args[0] - real_expr.parent = node.parent - # Search for node in all _astng_fields (the fields checked when - # get_children is called) of its parent. Some of those fields may - # be lists or tuples, in which case the elements need to be checked. - # When we find it, replace it by real_expr, so that the AST looks - # like no call to _TRANSIENT_FUNCTION ever took place. - for name in node.parent._astng_fields: - child = getattr(node.parent, name) - if isinstance(child, (list, tuple)): - for idx, compound_child in enumerate(child): - if compound_child is node: - child[idx] = real_expr - elif child is node: - setattr(node.parent, name, real_expr) - yield real_expr - else: - for child in node.get_children(): - for result in _extract_expressions(child): - yield result - - -def _find_statement_by_line(node, line): - """Extracts the statement on a specific line from an AST. - - If the line number of node matches line, it will be returned; - otherwise its children are iterated and the function is called - recursively. - - :param node: An astroid node. - :type node: astroid.bases.NodeNG - :param line: The line number of the statement to extract. - :type line: int - :returns: The statement on the line, or None if no statement for the line - can be found. - :rtype: astroid.bases.NodeNG or None - """ - if isinstance(node, (nodes.Class, nodes.Function)): - # This is an inaccuracy in the AST: the nodes that can be - # decorated do not carry explicit information on which line - # the actual definition (class/def), but .fromline seems to - # be close enough. - node_line = node.fromlineno - else: - node_line = node.lineno - - if node_line == line: - return node - - for child in node.get_children(): - result = _find_statement_by_line(child, line) - if result: - return result - - return None - -def extract_node(code, module_name=''): - """Parses some Python code as a module and extracts a designated AST node. - - Statements: - To extract one or more statement nodes, append #@ to the end of the line - - Examples: - >>> def x(): - >>> def y(): - >>> return 1 #@ - - The return statement will be extracted. - - >>> class X(object): - >>> def meth(self): #@ - >>> pass - - The funcion object 'meth' will be extracted. - - Expressions: - To extract arbitrary expressions, surround them with the fake - function call __(...). After parsing, the surrounded expression - will be returned and the whole AST (accessible via the returned - node's parent attribute) will look like the function call was - never there in the first place. - - Examples: - >>> a = __(1) - - The const node will be extracted. - - >>> def x(d=__(foo.bar)): pass - - The node containing the default argument will be extracted. - - >>> def foo(a, b): - >>> return 0 < __(len(a)) < b - - The node containing the function call 'len' will be extracted. - - If no statements or expressions are selected, the last toplevel - statement will be returned. - - If the selected statement is a discard statement, (i.e. an expression - turned into a statement), the wrapped expression is returned instead. - - For convenience, singleton lists are unpacked. - - :param str code: A piece of Python code that is parsed as - a module. Will be passed through textwrap.dedent first. - :param str module_name: The name of the module. - :returns: The designated node from the parse tree, or a list of nodes. - :rtype: astroid.bases.NodeNG, or a list of nodes. - """ - def _extract(node): - if isinstance(node, nodes.Discard): - return node.value - else: - return node - - requested_lines = [] - for idx, line in enumerate(code.splitlines()): - if line.strip().endswith(_STATEMENT_SELECTOR): - requested_lines.append(idx + 1) - - tree = build_module(code, module_name=module_name) - extracted = [] - if requested_lines: - for line in requested_lines: - extracted.append(_find_statement_by_line(tree, line)) - else: - # Modifies the tree. - extracted = list(_extract_expressions(tree)) - - if not extracted: - extracted.append(tree.body[-1]) - - extracted = [_extract(node) for node in extracted] - if len(extracted) == 1: - return extracted[0] - else: - return extracted - - -def build_module(code, module_name=''): - """Parses a string module with a builder. - :param code: The code for the module. - :type code: str - :param module_name: The name for the module - :type module_name: str - :returns: The module AST. - :rtype: astroid.bases.NodeNG - """ - code = textwrap.dedent(code) - return builder.AstroidBuilder(None).string_build(code, modname=module_name) diff -Nru astroid-1.0.1/tox.ini astroid-1.3.8/tox.ini --- astroid-1.0.1/tox.ini 1970-01-01 00:00:00.000000000 +0000 +++ astroid-1.3.8/tox.ini 2015-08-02 19:35:46.000000000 +0000 @@ -0,0 +1,19 @@ +[tox] +# official list is +#envlist = py27, py33, py34 +envlist = py27, py33, pylint + +[testenv:pylint] +deps = + logilab-common + six + hg+https://bitbucket.org/logilab/astroid + pylint==1.4.3 +commands = pylint -rn --rcfile={toxinidir}/pylintrc {envsitepackagesdir}/astroid + +[testenv] +deps = + logilab-common + six + +commands = python -m unittest discover -s {envsitepackagesdir}/astroid/tests -p "unittest*.py" diff -Nru astroid-1.0.1/utils.py astroid-1.3.8/utils.py --- astroid-1.0.1/utils.py 2013-07-29 15:04:25.000000000 +0000 +++ astroid-1.3.8/utils.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,236 +0,0 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr -# -# This file is part of astroid. -# -# astroid is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. -# -# astroid is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -# for more details. -# -# You should have received a copy of the GNU Lesser General Public License along -# with astroid. If not, see . -"""this module contains some utilities to navigate in the tree or to -extract information from it -""" - -__docformat__ = "restructuredtext en" - -from astroid.exceptions import AstroidBuildingException -from astroid.builder import parse - - -class ASTWalker: - """a walker visiting a tree in preorder, calling on the handler: - - * visit_ on entering a node, where class name is the class of - the node in lower case - - * leave_ on leaving a node, where class name is the class of - the node in lower case - """ - - def __init__(self, handler): - self.handler = handler - self._cache = {} - - def walk(self, node, _done=None): - """walk on the tree from , getting callbacks from handler""" - if _done is None: - _done = set() - if node in _done: - raise AssertionError((id(node), node, node.parent)) - _done.add(node) - self.visit(node) - for child_node in node.get_children(): - self.handler.set_context(node, child_node) - assert child_node is not node - self.walk(child_node, _done) - self.leave(node) - assert node.parent is not node - - def get_callbacks(self, node): - """get callbacks from handler for the visited node""" - klass = node.__class__ - methods = self._cache.get(klass) - if methods is None: - handler = self.handler - kid = klass.__name__.lower() - e_method = getattr(handler, 'visit_%s' % kid, - getattr(handler, 'visit_default', None)) - l_method = getattr(handler, 'leave_%s' % kid, - getattr(handler, 'leave_default', None)) - self._cache[klass] = (e_method, l_method) - else: - e_method, l_method = methods - return e_method, l_method - - def visit(self, node): - """walk on the tree from , getting callbacks from handler""" - method = self.get_callbacks(node)[0] - if method is not None: - method(node) - - def leave(self, node): - """walk on the tree from , getting callbacks from handler""" - method = self.get_callbacks(node)[1] - if method is not None: - method(node) - - -class LocalsVisitor(ASTWalker): - """visit a project by traversing the locals dictionary""" - def __init__(self): - ASTWalker.__init__(self, self) - self._visited = {} - - def visit(self, node): - """launch the visit starting from the given node""" - if node in self._visited: - return - self._visited[node] = 1 # FIXME: use set ? - methods = self.get_callbacks(node) - if methods[0] is not None: - methods[0](node) - if 'locals' in node.__dict__: # skip Instance and other proxy - for name, local_node in node.items(): - self.visit(local_node) - if methods[1] is not None: - return methods[1](node) - - -def _check_children(node): - """a helper function to check children - parent relations""" - for child in node.get_children(): - ok = False - if child is None: - print "Hm, child of %s is None" % node - continue - if not hasattr(child, 'parent'): - print " ERROR: %s has child %s %x with no parent" % (node, child, id(child)) - elif not child.parent: - print " ERROR: %s has child %s %x with parent %r" % (node, child, id(child), child.parent) - elif child.parent is not node: - print " ERROR: %s %x has child %s %x with wrong parent %s" % (node, - id(node), child, id(child), child.parent) - else: - ok = True - if not ok: - print "lines;", node.lineno, child.lineno - print "of module", node.root(), node.root().name - raise AstroidBuildingException - _check_children(child) - - -class TreeTester(object): - '''A helper class to see _ast tree and compare with astroid tree - - indent: string for tree indent representation - lineno: bool to tell if we should print the line numbers - - >>> tester = TreeTester('print') - >>> print tester.native_tree_repr() - - - . body = [ - . - . . nl = True - . ] - >>> print tester.astroid_tree_repr() - Module() - body = [ - Print() - dest = - values = [ - ] - ] - ''' - - indent = '. ' - lineno = False - - def __init__(self, sourcecode): - self._string = '' - self.sourcecode = sourcecode - self._ast_node = None - self.build_ast() - - def build_ast(self): - """build the _ast tree from the source code""" - self._ast_node = parse(self.sourcecode) - - def native_tree_repr(self, node=None, indent=''): - """get a nice representation of the _ast tree""" - self._string = '' - if node is None: - node = self._ast_node - self._native_repr_tree(node, indent) - return self._string - - - def _native_repr_tree(self, node, indent, _done=None): - """recursive method for the native tree representation""" - from _ast import Load as _Load, Store as _Store, Del as _Del - from _ast import AST as Node - if _done is None: - _done = set() - if node in _done: - self._string += '\nloop in tree: %r (%s)' % (node, - getattr(node, 'lineno', None)) - return - _done.add(node) - self._string += '\n' + indent + '<%s>' % node.__class__.__name__ - indent += self.indent - if not hasattr(node, '__dict__'): - self._string += '\n' + self.indent + " ** node has no __dict__ " + str(node) - return - node_dict = node.__dict__ - if hasattr(node, '_attributes'): - for a in node._attributes: - attr = node_dict[a] - if attr is None: - continue - if a in ("lineno", "col_offset") and not self.lineno: - continue - self._string +='\n' + indent + a + " = " + repr(attr) - for field in node._fields or (): - attr = node_dict[field] - if attr is None: - continue - if isinstance(attr, list): - if not attr: - continue - self._string += '\n' + indent + field + ' = [' - for elt in attr: - self._native_repr_tree(elt, indent, _done) - self._string += '\n' + indent + ']' - continue - if isinstance(attr, (_Load, _Store, _Del)): - continue - if isinstance(attr, Node): - self._string += '\n' + indent + field + " = " - self._native_repr_tree(attr, indent, _done) - else: - self._string += '\n' + indent + field + " = " + repr(attr) - - - def build_astroid_tree(self): - """build astroid tree from the _ast tree - """ - from astroid.builder import AstroidBuilder - tree = AstroidBuilder().string_build(self.sourcecode) - return tree - - def astroid_tree_repr(self, ids=False): - """build the astroid tree and return a nice tree representation""" - mod = self.build_astroid_tree() - return mod.repr_tree(ids) - - -__all__ = ('LocalsVisitor', 'ASTWalker',) -