Commit 807abf14 authored by Ned Nguyen's avatar Ned Nguyen Committed by Commit Bot

Revert "pylint: upgrade to 1.5.6"

This reverts commit 3899f1bc.

Reason for revert: causing PRESUBMIT error on catapult repo 

BUG:chromium:865897

Original change's description:
> pylint: upgrade to 1.5.6
> 
> We disable new warnings that are triggered in depot_tools to pylintrc.
> So the lint output before & after this CL are mostly unchanged.  The
> repos checked: depot_tools, src, and build.
> 
> Also update astroid to 1.4.9 and drop logilab.common as needed.
> 
> Bug: 863669
> Change-Id: Ib602560c1bcad5a9e8b6ca731d9465f43220f044
> Reviewed-on: https://chromium-review.googlesource.com/1137382
> Reviewed-by: John Budorick <jbudorick@chromium.org>
> Reviewed-by: Robbie Iannucci <iannucci@chromium.org>
> Commit-Queue: Mike Frysinger <vapier@chromium.org>

TBR=vapier@chromium.org,iannucci@chromium.org,jbudorick@chromium.org

Change-Id: I8ea087123db4e52fdf7ebff8b1ed356fd60a6059
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 863669
Reviewed-on: https://chromium-review.googlesource.com/1145160Reviewed-by: 's avatarNed Nguyen <nednguyen@google.com>
Commit-Queue: Ned Nguyen <nednguyen@google.com>
parent 3899f1bc
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
# pygtk.require(). # pygtk.require().
#init-hook= #init-hook=
# Profiled execution.
profile=no
# Add files or directories to the blacklist. They should be base names, not # Add files or directories to the blacklist. They should be base names, not
# paths. # paths.
ignore=CVS ignore=CVS
...@@ -90,53 +93,31 @@ disable= ...@@ -90,53 +93,31 @@ disable=
logging-not-lazy, logging-not-lazy,
bad-continuation, bad-continuation,
anomalous-backslash-in-string, anomalous-backslash-in-string,
assigning-non-slot,
bad-context-manager, bad-context-manager,
bad-indentation, bad-indentation,
bad-str-strip-call, bad-str-strip-call,
bad-super-call,
bad-whitespace, bad-whitespace,
cell-var-from-loop, cell-var-from-loop,
consider-using-enumerate,
deprecated-lambda, deprecated-lambda,
deprecated-method,
eval-used, eval-used,
function-redefined, function-redefined,
import-error, import-error,
locally-enabled, locally-enabled,
misplaced-comparison-constant,
misplaced-bare-raise,
missing-final-newline, missing-final-newline,
multiple-imports,
no-init, no-init,
no-name-in-module, no-name-in-module,
no-self-argument,
no-self-use, no-self-use,
not-an-iterable,
not-callable, not-callable,
old-style-class, old-style-class,
protected-access, protected-access,
redefined-variable-type,
simplifiable-if-statement,
singleton-comparison,
superfluous-parens, superfluous-parens,
super-on-old-class, super-on-old-class,
too-many-boolean-expressions,
too-many-function-args, too-many-function-args,
too-many-nested-blocks,
trailing-whitespace, trailing-whitespace,
undefined-variable,
ungrouped-imports,
unnecessary-semicolon, unnecessary-semicolon,
unneeded-not,
unpacking-non-sequence, unpacking-non-sequence,
unsubscriptable-object,
unsupported-membership-test,
unused-import, unused-import,
useless-else-on-loop, useless-else-on-loop
using-constant-test,
wrong-import-order,
wrong-import-position,
[REPORTS] [REPORTS]
...@@ -161,6 +142,10 @@ reports=no ...@@ -161,6 +142,10 @@ reports=no
# (RP0004). # (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Add a comment according to your evaluation note. This is used by the global
# evaluation report (RP0004).
comment=no
[VARIABLES] [VARIABLES]
...@@ -186,6 +171,10 @@ ignore-mixin-members=yes ...@@ -186,6 +171,10 @@ ignore-mixin-members=yes
# (useful for classes with attributes dynamically set). # (useful for classes with attributes dynamically set).
ignored-classes=SQLObject,twisted.internet.reactor,hashlib,google.appengine.api.memcache ignored-classes=SQLObject,twisted.internet.reactor,hashlib,google.appengine.api.memcache
# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
zope=no
# List of members which are set dynamically and missed by pylint inference # List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular # system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted. # expressions are accepted.
...@@ -226,6 +215,9 @@ indent-string=' ' ...@@ -226,6 +215,9 @@ indent-string=' '
[BASIC] [BASIC]
# Required attributes for module, separated by a comma
required-attributes=
# List of builtins function names that should not be used, separated by a comma # List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input bad-functions=map,filter,apply,input
...@@ -304,6 +296,10 @@ max-public-methods=20 ...@@ -304,6 +296,10 @@ max-public-methods=20
[CLASSES] [CLASSES]
# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# List of method names used to declare (i.e. assign) instance attributes. # List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp defining-attr-methods=__init__,__new__,setUp
......
URL: https://github.com/PyCQA/astroid URL: https://github.com/PyCQA/astroid
Version: 1.4.9 Version: 1.3.8
License: GPL License: GPL
License File: LICENSE.txt License File: LICENSE.txt
......
...@@ -58,15 +58,13 @@ from astroid import inference ...@@ -58,15 +58,13 @@ from astroid import inference
# more stuff available # more stuff available
from astroid import raw_building from astroid import raw_building
from astroid.bases import Instance, BoundMethod, UnboundMethod from astroid.bases import YES, Instance, BoundMethod, UnboundMethod
from astroid.node_classes import are_exclusive, unpack_infer from astroid.node_classes import are_exclusive, unpack_infer
from astroid.scoped_nodes import builtin_lookup from astroid.scoped_nodes import builtin_lookup
from astroid.builder import parse
from astroid.util import YES
# make a manager instance (borg) as well as Project and Package classes # make a manager instance (borg) as well as Project and Package classes
# accessible from astroid package # accessible from astroid package
from astroid.manager import AstroidManager from astroid.manager import AstroidManager, Project
MANAGER = AstroidManager() MANAGER = AstroidManager()
del AstroidManager del AstroidManager
...@@ -102,7 +100,7 @@ def inference_tip(infer_function): ...@@ -102,7 +100,7 @@ def inference_tip(infer_function):
.. sourcecode:: python .. sourcecode:: python
MANAGER.register_transform(Call, inference_tip(infer_named_tuple), MANAGER.register_transform(CallFunc, inference_tip(infer_named_tuple),
predicate) predicate)
""" """
def transform(node, infer_function=infer_function): def transform(node, infer_function=infer_function):
...@@ -114,11 +112,8 @@ def inference_tip(infer_function): ...@@ -114,11 +112,8 @@ def inference_tip(infer_function):
def register_module_extender(manager, module_name, get_extension_mod): def register_module_extender(manager, module_name, get_extension_mod):
def transform(node): def transform(node):
extension_module = get_extension_mod() extension_module = get_extension_mod()
for name, objs in extension_module._locals.items(): for name, obj in extension_module.locals.items():
node._locals[name] = objs node.locals[name] = obj
for obj in objs:
if obj.parent is extension_module:
obj.parent = node
manager.register_transform(Module, transform, lambda n: n.name == module_name) manager.register_transform(Module, transform, lambda n: n.name == module_name)
......
...@@ -20,17 +20,17 @@ distname = 'astroid' ...@@ -20,17 +20,17 @@ distname = 'astroid'
modname = 'astroid' modname = 'astroid'
numversion = (1, 4, 9) numversion = (1, 3, 8)
version = '.'.join([str(num) for num in numversion]) version = '.'.join([str(num) for num in numversion])
install_requires = ['six', 'lazy_object_proxy', 'wrapt'] install_requires = ['logilab-common>=0.63.0', 'six']
license = 'LGPL' license = 'LGPL'
author = 'Python Code Quality Authority' author = 'Logilab'
author_email = 'code-quality@python.org' author_email = 'pylint-dev@lists.logilab.org'
mailinglist = "mailto://%s" % author_email mailinglist = "mailto://%s" % author_email
web = 'https://github.com/PyCQA/astroid' web = 'http://bitbucket.org/logilab/astroid'
description = "A abstract syntax tree for Python with inference support." description = "A abstract syntax tree for Python with inference support."
......
# 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 <http://www.gnu.org/licenses/>.
from astroid import bases
from astroid import context as contextmod
from astroid import exceptions
from astroid import nodes
from astroid import util
import six
class CallSite(object):
"""Class for understanding arguments passed into a call site
It needs a call context, which contains the arguments and the
keyword arguments that were passed into a given call site.
In order to infer what an argument represents, call
:meth:`infer_argument` with the corresponding function node
and the argument name.
"""
def __init__(self, callcontext):
args = callcontext.args
keywords = callcontext.keywords
self.duplicated_keywords = set()
self._unpacked_args = self._unpack_args(args)
self._unpacked_kwargs = self._unpack_keywords(keywords)
self.positional_arguments = [
arg for arg in self._unpacked_args
if arg is not util.YES
]
self.keyword_arguments = {
key: value for key, value in self._unpacked_kwargs.items()
if value is not util.YES
}
@classmethod
def from_call(cls, call_node):
"""Get a CallSite object from the given Call node."""
callcontext = contextmod.CallContext(call_node.args,
call_node.keywords)
return cls(callcontext)
def has_invalid_arguments(self):
"""Check if in the current CallSite were passed *invalid* arguments
This can mean multiple things. For instance, if an unpacking
of an invalid object was passed, then this method will return True.
Other cases can be when the arguments can't be inferred by astroid,
for example, by passing objects which aren't known statically.
"""
return len(self.positional_arguments) != len(self._unpacked_args)
def has_invalid_keywords(self):
"""Check if in the current CallSite were passed *invalid* keyword arguments
For instance, unpacking a dictionary with integer keys is invalid
(**{1:2}), because the keys must be strings, which will make this
method to return True. Other cases where this might return True if
objects which can't be inferred were passed.
"""
return len(self.keyword_arguments) != len(self._unpacked_kwargs)
def _unpack_keywords(self, keywords):
values = {}
context = contextmod.InferenceContext()
for name, value in keywords:
if name is None:
# Then it's an unpacking operation (**)
try:
inferred = next(value.infer(context=context))
except exceptions.InferenceError:
values[name] = util.YES
continue
if not isinstance(inferred, nodes.Dict):
# Not something we can work with.
values[name] = util.YES
continue
for dict_key, dict_value in inferred.items:
try:
dict_key = next(dict_key.infer(context=context))
except exceptions.InferenceError:
values[name] = util.YES
continue
if not isinstance(dict_key, nodes.Const):
values[name] = util.YES
continue
if not isinstance(dict_key.value, six.string_types):
values[name] = util.YES
continue
if dict_key.value in values:
# The name is already in the dictionary
values[dict_key.value] = util.YES
self.duplicated_keywords.add(dict_key.value)
continue
values[dict_key.value] = dict_value
else:
values[name] = value
return values
@staticmethod
def _unpack_args(args):
values = []
context = contextmod.InferenceContext()
for arg in args:
if isinstance(arg, nodes.Starred):
try:
inferred = next(arg.value.infer(context=context))
except exceptions.InferenceError:
values.append(util.YES)
continue
if inferred is util.YES:
values.append(util.YES)
continue
if not hasattr(inferred, 'elts'):
values.append(util.YES)
continue
values.extend(inferred.elts)
else:
values.append(arg)
return values
def infer_argument(self, funcnode, name, context):
"""infer a function argument value according to the call context"""
if name in self.duplicated_keywords:
raise exceptions.InferenceError(name)
# Look into the keywords first, maybe it's already there.
try:
return self.keyword_arguments[name].infer(context)
except KeyError:
pass
# Too many arguments given and no variable arguments.
if len(self.positional_arguments) > len(funcnode.args.args):
if not funcnode.args.vararg:
raise exceptions.InferenceError(name)
positional = self.positional_arguments[:len(funcnode.args.args)]
vararg = self.positional_arguments[len(funcnode.args.args):]
argindex = funcnode.args.find_argname(name)[0]
kwonlyargs = set(arg.name for arg in funcnode.args.kwonlyargs)
kwargs = {
key: value for key, value in self.keyword_arguments.items()
if key not in kwonlyargs
}
# If there are too few positionals compared to
# what the function expects to receive, check to see
# if the missing positional arguments were passed
# as keyword arguments and if so, place them into the
# positional args list.
if len(positional) < len(funcnode.args.args):
for func_arg in funcnode.args.args:
if func_arg.name in kwargs:
arg = kwargs.pop(func_arg.name)
positional.append(arg)
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, bases.Instance):
boundnode = bases.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.positional_arguments[argindex].infer(context)
except IndexError:
pass
if funcnode.args.kwarg == name:
# It wants all the keywords that were passed into
# the call site.
if self.has_invalid_keywords():
raise exceptions.InferenceError
kwarg = nodes.Dict()
kwarg.lineno = funcnode.args.lineno
kwarg.col_offset = funcnode.args.col_offset
kwarg.parent = funcnode.args
items = [(nodes.const_factory(key), value)
for key, value in kwargs.items()]
kwarg.items = items
return iter((kwarg, ))
elif funcnode.args.vararg == name:
# It wants all the args that were passed into
# the call site.
if self.has_invalid_arguments():
raise exceptions.InferenceError
args = nodes.Tuple()
args.lineno = funcnode.args.lineno
args.col_offset = funcnode.args.col_offset
args.parent = funcnode.args
args.elts = vararg
return iter((args, ))
# Check if it's a default parameter.
try:
return funcnode.args.default_value(name).infer(context)
except exceptions.NoDefault:
pass
raise exceptions.InferenceError(name)
...@@ -22,9 +22,8 @@ ...@@ -22,9 +22,8 @@
* :func:`dump` function return an internal representation of nodes found * :func:`dump` function return an internal representation of nodes found
in the tree, useful for debugging or understanding the tree structure in the tree, useful for debugging or understanding the tree structure
""" """
import sys
import six import sys
INDENT = ' ' # 4 spaces ; keep indentation variable INDENT = ' ' # 4 spaces ; keep indentation variable
...@@ -90,9 +89,9 @@ class AsStringVisitor(object): ...@@ -90,9 +89,9 @@ class AsStringVisitor(object):
"""return an astroid.Function node as string""" """return an astroid.Function node as string"""
return node.format_args() return node.format_args()
def visit_assignattr(self, node): def visit_assattr(self, node):
"""return an astroid.AssAttr node as string""" """return an astroid.AssAttr node as string"""
return self.visit_attribute(node) return self.visit_getattr(node)
def visit_assert(self, node): def visit_assert(self, node):
"""return an astroid.Assert node as string""" """return an astroid.Assert node as string"""
...@@ -101,7 +100,7 @@ class AsStringVisitor(object): ...@@ -101,7 +100,7 @@ class AsStringVisitor(object):
node.fail.accept(self)) node.fail.accept(self))
return 'assert %s' % node.test.accept(self) return 'assert %s' % node.test.accept(self)
def visit_assignname(self, node): def visit_assname(self, node):
"""return an astroid.AssName node as string""" """return an astroid.AssName node as string"""
return node.name return node.name
...@@ -114,8 +113,8 @@ class AsStringVisitor(object): ...@@ -114,8 +113,8 @@ class AsStringVisitor(object):
"""return an astroid.AugAssign node as string""" """return an astroid.AugAssign node as string"""
return '%s %s %s' % (node.target.accept(self), node.op, node.value.accept(self)) return '%s %s %s' % (node.target.accept(self), node.op, node.value.accept(self))
def visit_repr(self, node): def visit_backquote(self, node):
"""return an astroid.Repr node as string""" """return an astroid.Backquote node as string"""
return '`%s`' % node.value.accept(self) return '`%s`' % node.value.accept(self)
def visit_binop(self, node): def visit_binop(self, node):
...@@ -131,20 +130,18 @@ class AsStringVisitor(object): ...@@ -131,20 +130,18 @@ class AsStringVisitor(object):
"""return an astroid.Break node as string""" """return an astroid.Break node as string"""
return 'break' return 'break'
def visit_call(self, node): def visit_callfunc(self, node):
"""return an astroid.Call node as string""" """return an astroid.CallFunc node as string"""
expr_str = node.func.accept(self) expr_str = node.func.accept(self)
args = [arg.accept(self) for arg in node.args] args = [arg.accept(self) for arg in node.args]
if node.keywords: if node.starargs:
keywords = [kwarg.accept(self) for kwarg in node.keywords] args.append('*' + node.starargs.accept(self))
else: if node.kwargs:
keywords = [] args.append('**' + node.kwargs.accept(self))
args.extend(keywords)
return '%s(%s)' % (expr_str, ', '.join(args)) return '%s(%s)' % (expr_str, ', '.join(args))
def visit_classdef(self, node): def visit_class(self, node):
"""return an astroid.ClassDef node as string""" """return an astroid.Class node as string"""
decorate = node.decorators and node.decorators.accept(self) or '' decorate = node.decorators and node.decorators.accept(self) or ''
bases = ', '.join([n.accept(self) for n in node.bases]) bases = ', '.join([n.accept(self) for n in node.bases])
if sys.version_info[0] == 2: if sys.version_info[0] == 2:
...@@ -189,7 +186,7 @@ class AsStringVisitor(object): ...@@ -189,7 +186,7 @@ class AsStringVisitor(object):
def visit_delattr(self, node): def visit_delattr(self, node):
"""return an astroid.DelAttr node as string""" """return an astroid.DelAttr node as string"""
return self.visit_attribute(node) return self.visit_getattr(node)
def visit_delname(self, node): def visit_delname(self, node):
"""return an astroid.DelName node as string""" """return an astroid.DelName node as string"""
...@@ -201,27 +198,16 @@ class AsStringVisitor(object): ...@@ -201,27 +198,16 @@ class AsStringVisitor(object):
def visit_dict(self, node): def visit_dict(self, node):
"""return an astroid.Dict node as string""" """return an astroid.Dict node as string"""
return '{%s}' % ', '.join(self._visit_dict(node)) return '{%s}' % ', '.join(['%s: %s' % (key.accept(self),
value.accept(self))
def _visit_dict(self, node): for key, value in node.items])
for key, value in node.items:
key = key.accept(self)
value = value.accept(self)
if key == '**':
# It can only be a DictUnpack node.
yield key + value
else:
yield '%s: %s' % (key, value)
def visit_dictunpack(self, node):
return '**'
def visit_dictcomp(self, node): def visit_dictcomp(self, node):
"""return an astroid.DictComp node as string""" """return an astroid.DictComp node as string"""
return '{%s: %s %s}' % (node.key.accept(self), node.value.accept(self), return '{%s: %s %s}' % (node.key.accept(self), node.value.accept(self),
' '.join([n.accept(self) for n in node.generators])) ' '.join([n.accept(self) for n in node.generators]))
def visit_expr(self, node): def visit_discard(self, node):
"""return an astroid.Discard node as string""" """return an astroid.Discard node as string"""
return node.value.accept(self) return node.value.accept(self)
...@@ -272,33 +258,24 @@ class AsStringVisitor(object): ...@@ -272,33 +258,24 @@ class AsStringVisitor(object):
fors = '%s\nelse:\n%s' % (fors, self._stmt_list(node.orelse)) fors = '%s\nelse:\n%s' % (fors, self._stmt_list(node.orelse))
return fors return fors
def visit_importfrom(self, node): def visit_from(self, node):
"""return an astroid.ImportFrom node as string""" """return an astroid.From node as string"""
return 'from %s import %s' % ('.' * (node.level or 0) + node.modname, return 'from %s import %s' % ('.' * (node.level or 0) + node.modname,
_import_string(node.names)) _import_string(node.names))
def visit_functiondef(self, node): def visit_function(self, node):
"""return an astroid.Function node as string""" """return an astroid.Function node as string"""
decorate = node.decorators and node.decorators.accept(self) or '' decorate = node.decorators and node.decorators.accept(self) or ''
docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or ''
return_annotation = '' return '\n%sdef %s(%s):%s\n%s' % (decorate, node.name, node.args.accept(self),
if six.PY3 and node.returns: docs, self._stmt_list(node.body))
return_annotation = '->' + node.returns.as_string()
trailer = return_annotation + ":" def visit_genexpr(self, node):
else: """return an astroid.GenExpr node as string"""
trailer = ":"
def_format = "\n%sdef %s(%s)%s%s\n%s"
return def_format % (decorate, node.name,
node.args.accept(self),
trailer, docs,
self._stmt_list(node.body))
def visit_generatorexp(self, node):
"""return an astroid.GeneratorExp node as string"""
return '(%s %s)' % (node.elt.accept(self), return '(%s %s)' % (node.elt.accept(self),
' '.join([n.accept(self) for n in node.generators])) ' '.join([n.accept(self) for n in node.generators]))
def visit_attribute(self, node): def visit_getattr(self, node):
"""return an astroid.Getattr node as string""" """return an astroid.Getattr node as string"""
return '%s.%s' % (node.expr.accept(self), node.attrname) return '%s.%s' % (node.expr.accept(self), node.attrname)
...@@ -325,8 +302,6 @@ class AsStringVisitor(object): ...@@ -325,8 +302,6 @@ class AsStringVisitor(object):
def visit_keyword(self, node): def visit_keyword(self, node):
"""return an astroid.Keyword node as string""" """return an astroid.Keyword node as string"""
if node.arg is None:
return '**%s' % node.value.accept(self)
return '%s=%s' % (node.arg, node.value.accept(self)) return '%s=%s' % (node.arg, node.value.accept(self))
def visit_lambda(self, node): def visit_lambda(self, node):
...@@ -463,22 +438,6 @@ class AsStringVisitor(object): ...@@ -463,22 +438,6 @@ class AsStringVisitor(object):
else: else:
return "(%s)" % (expr,) return "(%s)" % (expr,)
def visit_starred(self, node):
"""return Starred node as string"""
return "*" + node.value.accept(self)
# These aren't for real AST nodes, but for inference objects.
def visit_frozenset(self, node):
return node.parent.accept(self)
def visit_super(self, node):
return node.parent.accept(self)
def visit_yes(self, node):
return "Uninferable"
class AsStringVisitor3k(AsStringVisitor): class AsStringVisitor3k(AsStringVisitor):
"""AsStringVisitor3k overwrites some AsStringVisitor methods""" """AsStringVisitor3k overwrites some AsStringVisitor methods"""
...@@ -507,6 +466,10 @@ class AsStringVisitor3k(AsStringVisitor): ...@@ -507,6 +466,10 @@ class AsStringVisitor3k(AsStringVisitor):
return 'raise %s' % node.exc.accept(self) return 'raise %s' % node.exc.accept(self)
return 'raise' return 'raise'
def visit_starred(self, node):
"""return Starred node as string"""
return "*" + node.value.accept(self)
def visit_yieldfrom(self, node): def visit_yieldfrom(self, node):
""" Return an astroid.YieldFrom node as string. """ """ Return an astroid.YieldFrom node as string. """
yi_val = node.value and (" " + node.value.accept(self)) or "" yi_val = node.value and (" " + node.value.accept(self)) or ""
...@@ -516,19 +479,6 @@ class AsStringVisitor3k(AsStringVisitor): ...@@ -516,19 +479,6 @@ class AsStringVisitor3k(AsStringVisitor):
else: else:
return "(%s)" % (expr,) return "(%s)" % (expr,)
def visit_asyncfunctiondef(self, node):
function = super(AsStringVisitor3k, self).visit_functiondef(node)
return 'async ' + function.strip()
def visit_await(self, node):
return 'await %s' % node.value.accept(self)
def visit_asyncwith(self, node):
return 'async %s' % self.visit_with(node)
def visit_asyncfor(self, node):
return 'async %s' % self.visit_for(node)
def _import_string(names): def _import_string(names):
"""return a list of (name, asname) formatted as a string""" """return a list of (name, asname) formatted as a string"""
...@@ -546,3 +496,4 @@ if sys.version_info >= (3, 0): ...@@ -546,3 +496,4 @@ if sys.version_info >= (3, 0):
# this visitor is stateless, thus it can be reused # this visitor is stateless, thus it can be reused
to_code = AsStringVisitor() to_code = AsStringVisitor()
This diff is collapsed.
"""Astroid hooks for dateutil"""
import textwrap
from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder
def dateutil_transform():
return AstroidBuilder(MANAGER).string_build(textwrap.dedent('''
import datetime
def parse(timestr, parserinfo=None, **kwargs):
return datetime.datetime()
'''))
register_module_extender(MANAGER, 'dateutil.parser', dateutil_transform)
# 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 <http://www.gnu.org/licenses/>.
"""Astroid hooks for numpy."""
import astroid
# TODO(cpopa): drop when understanding augmented assignments
def numpy_core_transform():
return astroid.parse('''
from numpy.core import numeric
from numpy.core import fromnumeric
from numpy.core import defchararray
from numpy.core import records
from numpy.core import function_base
from numpy.core import machar
from numpy.core import getlimits
from numpy.core import shape_base
__all__ = (['char', 'rec', 'memmap', 'chararray'] + numeric.__all__ +
fromnumeric.__all__ +
records.__all__ +
function_base.__all__ +
machar.__all__ +
getlimits.__all__ +
shape_base.__all__)
''')
def numpy_transform():
return astroid.parse('''
from numpy import core
from numpy import matrixlib as _mat
from numpy import lib
__all__ = ['add_newdocs',
'ModuleDeprecationWarning',
'VisibleDeprecationWarning', 'linalg', 'fft', 'random',
'ctypeslib', 'ma',
'__version__', 'pkgload', 'PackageLoader',
'show_config'] + core.__all__ + _mat.__all__ + lib.__all__
''')
astroid.register_module_extender(astroid.MANAGER, 'numpy.core', numpy_core_transform)
astroid.register_module_extender(astroid.MANAGER, 'numpy', numpy_transform)
"""Astroid hooks for the PyQT library."""
from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder
from astroid import nodes
from astroid import parse
def _looks_like_signal(node, signal_name='pyqtSignal'):
if '__class__' in node._instance_attrs:
cls = node._instance_attrs['__class__'][0]
return cls.name == signal_name
return False
def transform_pyqt_signal(node):
module = parse('''
class pyqtSignal(object):
def connect(self, slot, type=None, no_receiver_check=False):
pass
def disconnect(self, slot):
pass
def emit(self, *args):
pass
''')
signal_cls = module['pyqtSignal']
node._instance_attrs['emit'] = signal_cls['emit']
node._instance_attrs['disconnect'] = signal_cls['disconnect']
node._instance_attrs['connect'] = signal_cls['connect']
def pyqt4_qtcore_transform():
return AstroidBuilder(MANAGER).string_build('''
def SIGNAL(signal_name): pass
class QObject(object):
def emit(self, signal): pass
''')
register_module_extender(MANAGER, 'PyQt4.QtCore', pyqt4_qtcore_transform)
MANAGER.register_transform(nodes.FunctionDef, transform_pyqt_signal,
_looks_like_signal)
\ No newline at end of file
"""Astroid hooks for the ssl library."""
from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder
from astroid import nodes
from astroid import parse
def ssl_transform():
return parse('''
from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
from _ssl import _SSLContext, MemoryBIO
from _ssl import (
SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError,
SSLSyscallError, SSLEOFError,
)
from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj
from _ssl import RAND_status, RAND_add, RAND_bytes, RAND_pseudo_bytes
try:
from _ssl import RAND_egd
except ImportError:
# LibreSSL does not provide RAND_egd
pass
from _ssl import (OP_ALL, OP_CIPHER_SERVER_PREFERENCE,
OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3,
OP_NO_TLSv1, OP_NO_TLSv1_1, OP_NO_TLSv1_2,
OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE)
from _ssl import (ALERT_DESCRIPTION_ACCESS_DENIED, ALERT_DESCRIPTION_BAD_CERTIFICATE,
ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE,
ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE,
ALERT_DESCRIPTION_BAD_RECORD_MAC,
ALERT_DESCRIPTION_CERTIFICATE_EXPIRED,
ALERT_DESCRIPTION_CERTIFICATE_REVOKED,
ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN,
ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE,
ALERT_DESCRIPTION_CLOSE_NOTIFY, ALERT_DESCRIPTION_DECODE_ERROR,
ALERT_DESCRIPTION_DECOMPRESSION_FAILURE,
ALERT_DESCRIPTION_DECRYPT_ERROR,
ALERT_DESCRIPTION_HANDSHAKE_FAILURE,
ALERT_DESCRIPTION_ILLEGAL_PARAMETER,
ALERT_DESCRIPTION_INSUFFICIENT_SECURITY,
ALERT_DESCRIPTION_INTERNAL_ERROR,
ALERT_DESCRIPTION_NO_RENEGOTIATION,
ALERT_DESCRIPTION_PROTOCOL_VERSION,
ALERT_DESCRIPTION_RECORD_OVERFLOW,
ALERT_DESCRIPTION_UNEXPECTED_MESSAGE,
ALERT_DESCRIPTION_UNKNOWN_CA,
ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY,
ALERT_DESCRIPTION_UNRECOGNIZED_NAME,
ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE,
ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION,
ALERT_DESCRIPTION_USER_CANCELLED)
from _ssl import (SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, SSL_ERROR_SSL,
SSL_ERROR_SYSCALL, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_READ,
SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_X509_LOOKUP, SSL_ERROR_ZERO_RETURN)
from _ssl import VERIFY_CRL_CHECK_CHAIN, VERIFY_CRL_CHECK_LEAF, VERIFY_DEFAULT, VERIFY_X509_STRICT
from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN
from _ssl import _OPENSSL_API_VERSION
from _ssl import PROTOCOL_SSLv23, PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2
''')
register_module_extender(MANAGER, 'ssl', ssl_transform)
...@@ -7,11 +7,9 @@ from textwrap import dedent ...@@ -7,11 +7,9 @@ from textwrap import dedent
import six import six
from astroid import (MANAGER, UseInferenceDefault, from astroid import (MANAGER, UseInferenceDefault,
inference_tip, YES, InferenceError, UnresolvableName) inference_tip, YES, InferenceError, UnresolvableName)
from astroid import arguments
from astroid import nodes from astroid import nodes
from astroid import objects
from astroid.builder import AstroidBuilder from astroid.builder import AstroidBuilder
from astroid import util
def _extend_str(class_node, rvalue): def _extend_str(class_node, rvalue):
"""function to extend builtin str/unicode class""" """function to extend builtin str/unicode class"""
...@@ -53,7 +51,7 @@ def _extend_str(class_node, rvalue): ...@@ -53,7 +51,7 @@ def _extend_str(class_node, rvalue):
def rstrip(self, chars=None): def rstrip(self, chars=None):
return {rvalue} return {rvalue}
def rjust(self, width, fillchar=None): def rjust(self, width, fillchar=None):
return {rvalue} return {rvalue}
def center(self, width, fillchar=None): def center(self, width, fillchar=None):
return {rvalue} return {rvalue}
def ljust(self, width, fillchar=None): def ljust(self, width, fillchar=None):
...@@ -62,7 +60,7 @@ def _extend_str(class_node, rvalue): ...@@ -62,7 +60,7 @@ def _extend_str(class_node, rvalue):
code = code.format(rvalue=rvalue) code = code.format(rvalue=rvalue)
fake = AstroidBuilder(MANAGER).string_build(code)['whatever'] fake = AstroidBuilder(MANAGER).string_build(code)['whatever']
for method in fake.mymethods(): for method in fake.mymethods():
class_node._locals[method.name] = [method] class_node.locals[method.name] = [method]
method.parent = class_node method.parent = class_node
def extend_builtins(class_transforms): def extend_builtins(class_transforms):
...@@ -88,17 +86,12 @@ def register_builtin_transform(transform, builtin_name): ...@@ -88,17 +86,12 @@ def register_builtin_transform(transform, builtin_name):
def _transform_wrapper(node, context=None): def _transform_wrapper(node, context=None):
result = transform(node, context=context) result = transform(node, context=context)
if result: if result:
if not result.parent: result.parent = node
# Let the transformation function determine
# the parent for its result. Otherwise,
# we set it to be the node we transformed from.
result.parent = node
result.lineno = node.lineno result.lineno = node.lineno
result.col_offset = node.col_offset result.col_offset = node.col_offset
return iter([result]) return iter([result])
MANAGER.register_transform(nodes.Call, MANAGER.register_transform(nodes.CallFunc,
inference_tip(_transform_wrapper), inference_tip(_transform_wrapper),
lambda n: (isinstance(n.func, nodes.Name) and lambda n: (isinstance(n.func, nodes.Name) and
n.func.name == builtin_name)) n.func.name == builtin_name))
...@@ -115,13 +108,13 @@ def _generic_inference(node, context, node_type, transform): ...@@ -115,13 +108,13 @@ def _generic_inference(node, context, node_type, transform):
transformed = transform(arg) transformed = transform(arg)
if not transformed: if not transformed:
try: try:
inferred = next(arg.infer(context=context)) infered = next(arg.infer(context=context))
except (InferenceError, StopIteration): except (InferenceError, StopIteration):
raise UseInferenceDefault() raise UseInferenceDefault()
if inferred is util.YES: if infered is YES:
raise UseInferenceDefault() raise UseInferenceDefault()
transformed = transform(inferred) transformed = transform(infered)
if not transformed or transformed is util.YES: if not transformed or transformed is YES:
raise UseInferenceDefault() raise UseInferenceDefault()
return transformed return transformed
...@@ -179,25 +172,19 @@ infer_set = partial( ...@@ -179,25 +172,19 @@ infer_set = partial(
iterables=(nodes.List, nodes.Tuple), iterables=(nodes.List, nodes.Tuple),
build_elts=set) build_elts=set)
infer_frozenset = partial(
_infer_builtin,
klass=objects.FrozenSet,
iterables=(nodes.List, nodes.Tuple, nodes.Set),
build_elts=frozenset)
def _get_elts(arg, context): def _get_elts(arg, context):
is_iterable = lambda n: isinstance(n, is_iterable = lambda n: isinstance(n,
(nodes.List, nodes.Tuple, nodes.Set)) (nodes.List, nodes.Tuple, nodes.Set))
try: try:
inferred = next(arg.infer(context)) infered = next(arg.infer(context))
except (InferenceError, UnresolvableName): except (InferenceError, UnresolvableName):
raise UseInferenceDefault() raise UseInferenceDefault()
if isinstance(inferred, nodes.Dict): if isinstance(infered, nodes.Dict):
items = inferred.items items = infered.items
elif is_iterable(inferred): elif is_iterable(infered):
items = [] items = []
for elt in inferred.elts: for elt in infered.elts:
# If an item is not a pair of two items, # If an item is not a pair of two items,
# then fallback to the default inference. # then fallback to the default inference.
# Also, take in consideration only hashable items, # Also, take in consideration only hashable items,
...@@ -226,28 +213,24 @@ def infer_dict(node, context=None): ...@@ -226,28 +213,24 @@ def infer_dict(node, context=None):
* dict(mapping, **kwargs) * dict(mapping, **kwargs)
* dict(**kwargs) * dict(**kwargs)
If a case can't be inferred, we'll fallback to default inference. If a case can't be infered, we'll fallback to default inference.
""" """
call = arguments.CallSite.from_call(node) has_keywords = lambda args: all(isinstance(arg, nodes.Keyword)
if call.has_invalid_arguments() or call.has_invalid_keywords(): for arg in args)
raise UseInferenceDefault if not node.args and not node.kwargs:
args = call.positional_arguments
kwargs = list(call.keyword_arguments.items())
if not args and not kwargs:
# dict() # dict()
return nodes.Dict() return nodes.Dict()
elif kwargs and not args: elif has_keywords(node.args) and node.args:
# dict(a=1, b=2, c=4) # dict(a=1, b=2, c=4)
items = [(nodes.Const(key), value) for key, value in kwargs] items = [(nodes.Const(arg.arg), arg.value) for arg in node.args]
elif len(args) == 1 and kwargs: elif (len(node.args) >= 2 and
has_keywords(node.args[1:])):
# dict(some_iterable, b=2, c=4) # dict(some_iterable, b=2, c=4)
elts = _get_elts(args[0], context) elts = _get_elts(node.args[0], context)
keys = [(nodes.Const(key), value) for key, value in kwargs] keys = [(nodes.Const(arg.arg), arg.value) for arg in node.args[1:]]
items = elts + keys items = elts + keys
elif len(args) == 1: elif len(node.args) == 1:
items = _get_elts(args[0], context) items = _get_elts(node.args[0], context)
else: else:
raise UseInferenceDefault() raise UseInferenceDefault()
...@@ -255,82 +238,8 @@ def infer_dict(node, context=None): ...@@ -255,82 +238,8 @@ def infer_dict(node, context=None):
empty.items = items empty.items = items
return empty return empty
def _node_class(node):
klass = node.frame()
while klass is not None and not isinstance(klass, nodes.ClassDef):
if klass.parent is None:
klass = None
else:
klass = klass.parent.frame()
return klass
def infer_super(node, context=None):
"""Understand super calls.
There are some restrictions for what can be understood:
* unbounded super (one argument form) is not understood.
* if the super call is not inside a function (classmethod or method),
then the default inference will be used.
* if the super arguments can't be infered, the default inference
will be used.
"""
if len(node.args) == 1:
# Ignore unbounded super.
raise UseInferenceDefault
scope = node.scope()
if not isinstance(scope, nodes.FunctionDef):
# Ignore non-method uses of super.
raise UseInferenceDefault
if scope.type not in ('classmethod', 'method'):
# Not interested in staticmethods.
raise UseInferenceDefault
cls = _node_class(scope)
if not len(node.args):
mro_pointer = cls
# In we are in a classmethod, the interpreter will fill
# automatically the class as the second argument, not an instance.
if scope.type == 'classmethod':
mro_type = cls
else:
mro_type = cls.instantiate_class()
else:
# TODO(cpopa): support flow control (multiple inference values).
try:
mro_pointer = next(node.args[0].infer(context=context))
except InferenceError:
raise UseInferenceDefault
try:
mro_type = next(node.args[1].infer(context=context))
except InferenceError:
raise UseInferenceDefault
if mro_pointer is YES or mro_type is YES:
# No way we could understand this.
raise UseInferenceDefault
super_obj = objects.Super(mro_pointer=mro_pointer,
mro_type=mro_type,
self_class=cls,
scope=scope)
super_obj.parent = node
return iter([super_obj])
# Builtins inference # Builtins inference
MANAGER.register_transform(nodes.Call,
inference_tip(infer_super),
lambda n: (isinstance(n.func, nodes.Name) and
n.func.name == 'super'))
register_builtin_transform(infer_tuple, 'tuple') register_builtin_transform(infer_tuple, 'tuple')
register_builtin_transform(infer_set, 'set') register_builtin_transform(infer_set, 'set')
register_builtin_transform(infer_list, 'list') register_builtin_transform(infer_list, 'list')
register_builtin_transform(infer_dict, 'dict') register_builtin_transform(infer_dict, 'dict')
register_builtin_transform(infer_frozenset, 'frozenset')
...@@ -7,9 +7,8 @@ import inspect ...@@ -7,9 +7,8 @@ import inspect
import itertools import itertools
import sys import sys
import re import re
import warnings
from astroid import MANAGER, AstroidBuildingException, nodes from astroid import MANAGER, AstroidBuildingException
from astroid.builder import AstroidBuilder from astroid.builder import AstroidBuilder
...@@ -47,13 +46,13 @@ def _gi_build_stub(parent): ...@@ -47,13 +46,13 @@ def _gi_build_stub(parent):
elif (inspect.ismethod(obj) or elif (inspect.ismethod(obj) or
inspect.ismethoddescriptor(obj)): inspect.ismethoddescriptor(obj)):
methods[name] = obj methods[name] = obj
elif type(obj) in [int, str]:
constants[name] = obj
elif (str(obj).startswith("<flags") or elif (str(obj).startswith("<flags") or
str(obj).startswith("<enum ") or str(obj).startswith("<enum ") or
str(obj).startswith("<GType ") or str(obj).startswith("<GType ") or
inspect.isdatadescriptor(obj)): inspect.isdatadescriptor(obj)):
constants[name] = 0 constants[name] = 0
elif isinstance(obj, (int, str)):
constants[name] = obj
elif callable(obj): elif callable(obj):
# Fall back to a function for anything callable # Fall back to a function for anything callable
functions[name] = obj functions[name] = obj
...@@ -74,7 +73,7 @@ def _gi_build_stub(parent): ...@@ -74,7 +73,7 @@ def _gi_build_stub(parent):
val = constants[name] val = constants[name]
strval = str(val) strval = str(val)
if isinstance(val, str): if type(val) is str:
strval = '"%s"' % str(val).replace("\\", "\\\\") strval = '"%s"' % str(val).replace("\\", "\\\\")
ret += "%s = %s\n" % (name, strval) ret += "%s = %s\n" % (name, strval)
...@@ -83,6 +82,7 @@ def _gi_build_stub(parent): ...@@ -83,6 +82,7 @@ def _gi_build_stub(parent):
if functions: if functions:
ret += "# %s functions\n\n" % parent.__name__ ret += "# %s functions\n\n" % parent.__name__
for name in sorted(functions): for name in sorted(functions):
func = functions[name]
ret += "def %s(*args, **kwargs):\n" % name ret += "def %s(*args, **kwargs):\n" % name
ret += " pass\n" ret += " pass\n"
...@@ -91,6 +91,7 @@ def _gi_build_stub(parent): ...@@ -91,6 +91,7 @@ def _gi_build_stub(parent):
if methods: if methods:
ret += "# %s methods\n\n" % parent.__name__ ret += "# %s methods\n\n" % parent.__name__
for name in sorted(methods): for name in sorted(methods):
func = methods[name]
ret += "def %s(self, *args, **kwargs):\n" % name ret += "def %s(self, *args, **kwargs):\n" % name
ret += " pass\n" ret += " pass\n"
...@@ -134,16 +135,7 @@ def _import_gi_module(modname): ...@@ -134,16 +135,7 @@ def _import_gi_module(modname):
for m in itertools.chain(modnames, optional_modnames): for m in itertools.chain(modnames, optional_modnames):
try: try:
__import__(m) __import__(m)
with warnings.catch_warnings(): modcode += _gi_build_stub(sys.modules[m])
# Just inspecting the code can raise gi deprecation
# warnings, so ignore them.
try:
from gi import PyGIDeprecationWarning
warnings.simplefilter("ignore", PyGIDeprecationWarning)
except Exception:
pass
modcode += _gi_build_stub(sys.modules[m])
except ImportError: except ImportError:
if m not in optional_modnames: if m not in optional_modnames:
raise raise
...@@ -158,38 +150,6 @@ def _import_gi_module(modname): ...@@ -158,38 +150,6 @@ def _import_gi_module(modname):
raise AstroidBuildingException('Failed to import module %r' % modname) raise AstroidBuildingException('Failed to import module %r' % modname)
return astng return astng
def _looks_like_require_version(node):
# Return whether this looks like a call to gi.require_version(<name>, <version>)
# Only accept function calls with two constant arguments
if len(node.args) != 2:
return False
if not all(isinstance(arg, nodes.Const) for arg in node.args):
return False
func = node.func
if isinstance(func, nodes.Attribute):
if func.attrname != 'require_version':
return False
if isinstance(func.expr, nodes.Name) and func.expr.name == 'gi':
return True
return False
if isinstance(func, nodes.Name):
return func.name == 'require_version'
return False
def _register_require_version(node):
# Load the gi.require_version locally
try:
import gi
gi.require_version(node.args[0].value, node.args[1].value)
except Exception:
pass
return node
MANAGER.register_failed_import_hook(_import_gi_module) MANAGER.register_failed_import_hook(_import_gi_module)
MANAGER.register_transform(nodes.Call, _register_require_version, _looks_like_require_version)
"""Astroid hooks for pytest.""" """Astroid hooks for pytest."""
from __future__ import absolute_import
from astroid import MANAGER, register_module_extender from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder from astroid.builder import AstroidBuilder
def pytest_transform(): def pytest_transform():
return AstroidBuilder(MANAGER).string_build(''' return AstroidBuilder(MANAGER).string_build('''
try: try:
import _pytest.mark import _pytest.mark
import _pytest.recwarn import _pytest.recwarn
import _pytest.runner import _pytest.runner
import _pytest.python import _pytest.python
import _pytest.skipping except ImportError:
import _pytest.assertion pass
except ImportError: else:
pass deprecated_call = _pytest.recwarn.deprecated_call
else: exit = _pytest.runner.exit
deprecated_call = _pytest.recwarn.deprecated_call fail = _pytest.runner.fail
warns = _pytest.recwarn.warns fixture = _pytest.python.fixture
importorskip = _pytest.runner.importorskip
exit = _pytest.runner.exit mark = _pytest.mark.MarkGenerator()
fail = _pytest.runner.fail raises = _pytest.python.raises
skip = _pytest.runner.skip skip = _pytest.runner.skip
importorskip = _pytest.runner.importorskip yield_fixture = _pytest.python.yield_fixture
xfail = _pytest.skipping.xfail ''')
mark = _pytest.mark.MarkGenerator()
raises = _pytest.python.raises register_module_extender(MANAGER, 'pytest', pytest_transform)
register_module_extender(MANAGER, 'py.test', pytest_transform)
# New in pytest 3.0
try:
approx = _pytest.python.approx
register_assert_rewrite = _pytest.assertion.register_assert_rewrite
except AttributeError:
pass
# Moved in pytest 3.0
try:
import _pytest.freeze_support
freeze_includes = _pytest.freeze_support.freeze_includes
except ImportError:
try:
import _pytest.genscript
freeze_includes = _pytest.genscript.freeze_includes
except ImportError:
pass
try:
import _pytest.debugging
set_trace = _pytest.debugging.pytestPDB().set_trace
except ImportError:
try:
import _pytest.pdb
set_trace = _pytest.pdb.pytestPDB().set_trace
except ImportError:
pass
try:
import _pytest.fixtures
fixture = _pytest.fixtures.fixture
yield_fixture = _pytest.fixtures.yield_fixture
except ImportError:
try:
import _pytest.python
fixture = _pytest.python.fixture
yield_fixture = _pytest.python.yield_fixture
except ImportError:
pass
''')
register_module_extender(MANAGER, 'pytest', pytest_transform)
register_module_extender(MANAGER, 'py.test', pytest_transform)
"""Astroid hooks for the Python 2 qt4 module.
Currently help understanding of :
* PyQT4.QtCore
"""
from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder
def pyqt4_qtcore_transform():
return AstroidBuilder(MANAGER).string_build('''
def SIGNAL(signal_name): pass
class QObject(object):
def emit(self, signal): pass
''')
register_module_extender(MANAGER, 'PyQt4.QtCore', pyqt4_qtcore_transform)
...@@ -48,14 +48,11 @@ def _nose_tools_functions(): ...@@ -48,14 +48,11 @@ def _nose_tools_functions():
if method.name.startswith('assert') and '_' not in method.name: if method.name.startswith('assert') and '_' not in method.name:
pep8_name = _pep8(method.name) pep8_name = _pep8(method.name)
yield pep8_name, astroid.BoundMethod(method, case) yield pep8_name, astroid.BoundMethod(method, case)
if method.name == 'assertEqual':
# nose also exports assert_equals.
yield 'assert_equals', astroid.BoundMethod(method, case)
def _nose_tools_transform(node): def _nose_tools_transform(node):
for method_name, method in _nose_tools_functions(): for method_name, method in _nose_tools_functions():
node._locals[method_name] = [method] node.locals[method_name] = [method]
def _nose_tools_trivial_transform(): def _nose_tools_trivial_transform():
......
...@@ -23,12 +23,7 @@ from textwrap import dedent ...@@ -23,12 +23,7 @@ from textwrap import dedent
from astroid import MANAGER, register_module_extender from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder from astroid.builder import AstroidBuilder
from astroid.exceptions import AstroidBuildingException, InferenceError from astroid.exceptions import AstroidBuildingException
from astroid import nodes
SIX_ADD_METACLASS = 'six.add_metaclass'
def _indent(text, prefix, predicate=None): def _indent(text, prefix, predicate=None):
"""Adds 'prefix' to the beginning of selected lines in 'text'. """Adds 'prefix' to the beginning of selected lines in 'text'.
...@@ -259,30 +254,8 @@ def _six_fail_hook(modname): ...@@ -259,30 +254,8 @@ def _six_fail_hook(modname):
module.name = 'six.moves' module.name = 'six.moves'
return module return module
def transform_six_add_metaclass(node):
"""Check if the given class node is decorated with *six.add_metaclass*
If so, inject its argument as the metaclass of the underlying class.
"""
if not node.decorators:
return
for decorator in node.decorators.nodes:
if not isinstance(decorator, nodes.Call):
continue
try:
func = next(decorator.func.infer())
except InferenceError:
continue
if func.qname() == SIX_ADD_METACLASS and decorator.args:
metaclass = decorator.args[0]
node._metaclass = metaclass
return node
register_module_extender(MANAGER, 'six', six_moves_transform) register_module_extender(MANAGER, 'six', six_moves_transform)
register_module_extender(MANAGER, 'requests.packages.urllib3.packages.six', register_module_extender(MANAGER, 'requests.packages.urllib3.packages.six',
six_moves_transform) six_moves_transform)
MANAGER.register_failed_import_hook(_six_fail_hook) MANAGER.register_failed_import_hook(_six_fail_hook)
MANAGER.register_transform(nodes.ClassDef, transform_six_add_metaclass)
This diff is collapsed.
# 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 <http://www.gnu.org/licenses/>.
"""Various context related utilities, including inference and call contexts."""
import contextlib
class InferenceContext(object):
__slots__ = ('path', 'lookupname', 'callcontext', 'boundnode', 'inferred')
def __init__(self, path=None, inferred=None):
self.path = path or set()
self.lookupname = None
self.callcontext = None
self.boundnode = None
self.inferred = inferred 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, inferred=self.inferred)
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.inferred[key] = tuple(results)
return
@contextlib.contextmanager
def restore_path(self):
path = set(self.path)
yield
self.path = path
class CallContext(object):
"""Holds information for a call site."""
__slots__ = ('args', 'keywords')
def __init__(self, args, keywords=None):
self.args = args
if keywords:
keywords = [(arg.arg, arg.value) for arg in keywords]
else:
keywords = []
self.keywords = keywords
def copy_context(context):
if context is not None:
return context.clone()
else:
return InferenceContext()
# 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 <http://www.gnu.org/licenses/>.
#
# The code in this file was originally part of logilab-common, licensed under
# the same license.
""" A few useful function/method decorators."""
import wrapt
@wrapt.decorator
def cached(func, instance, args, kwargs):
"""Simple decorator to cache result of method calls without args."""
cache = getattr(instance, '__cache', None)
if cache is None:
instance.__cache = cache = {}
try:
return cache[func]
except KeyError:
cache[func] = result = func(*args, **kwargs)
return result
class cachedproperty(object):
""" Provides a cached property equivalent to the stacking of
@cached and @property, but more efficient.
After first usage, the <property_name> becomes part of the object's
__dict__. Doing:
del obj.<property_name> empties the cache.
Idea taken from the pyramid_ framework and the mercurial_ project.
.. _pyramid: http://pypi.python.org/pypi/pyramid
.. _mercurial: http://pypi.python.org/pypi/Mercurial
"""
__slots__ = ('wrapped',)
def __init__(self, wrapped):
try:
wrapped.__name__
except AttributeError:
raise TypeError('%s must have a __name__ attribute' %
wrapped)
self.wrapped = wrapped
@property
def __doc__(self):
doc = getattr(self.wrapped, '__doc__', None)
return ('<wrapped by the cachedproperty decorator>%s'
% ('\n%s' % doc if doc else ''))
def __get__(self, inst, objtype=None):
if inst is None:
return self
val = self.wrapped(inst)
setattr(inst, self.wrapped.__name__, val)
return val
...@@ -30,26 +30,6 @@ class AstroidBuildingException(AstroidError): ...@@ -30,26 +30,6 @@ class AstroidBuildingException(AstroidError):
class ResolveError(AstroidError): class ResolveError(AstroidError):
"""base class of astroid resolution/inference error""" """base class of astroid resolution/inference error"""
class MroError(ResolveError):
"""Error raised when there is a problem with method resolution of a class."""
class DuplicateBasesError(MroError):
"""Error raised when there are duplicate bases in the same class bases."""
class InconsistentMroError(MroError):
"""Error raised when a class's MRO is inconsistent."""
class SuperError(ResolveError):
"""Error raised when there is a problem with a super call."""
class SuperArgumentTypeError(SuperError):
"""Error raised when the super arguments are invalid."""
class NotFoundError(ResolveError): class NotFoundError(ResolveError):
"""raised when we are unable to resolve a name""" """raised when we are unable to resolve a name"""
......
This diff is collapsed.
This diff is collapsed.
...@@ -18,16 +18,16 @@ ...@@ -18,16 +18,16 @@
"""This module contains some mixins for the different nodes. """This module contains some mixins for the different nodes.
""" """
import warnings from logilab.common.decorators import cachedproperty
from astroid import decorators from astroid.exceptions import (AstroidBuildingException, InferenceError,
from astroid import exceptions NotFoundError)
class BlockRangeMixIn(object): class BlockRangeMixIn(object):
"""override block range """ """override block range """
@decorators.cachedproperty @cachedproperty
def blockstart_tolineno(self): def blockstart_tolineno(self):
return self.lineno return self.lineno
...@@ -55,28 +55,14 @@ class FilterStmtsMixin(object): ...@@ -55,28 +55,14 @@ class FilterStmtsMixin(object):
return [node], True return [node], True
return _stmts, False return _stmts, False
def assign_type(self):
return self
def ass_type(self): def ass_type(self):
warnings.warn('%s.ass_type() is deprecated and slated for removal ' return self
'in astroid 2.0, use %s.assign_type() instead.'
% (type(self).__name__, type(self).__name__),
PendingDeprecationWarning, stacklevel=2)
return self.assign_type()
class AssignTypeMixin(object): class AssignTypeMixin(object):
def assign_type(self):
return self
def ass_type(self): def ass_type(self):
warnings.warn('%s.ass_type() is deprecated and slated for removal ' return self
'in astroid 2.0, use %s.assign_type() instead.'
% (type(self).__name__, type(self).__name__),
PendingDeprecationWarning, stacklevel=2)
return self.assign_type()
def _get_filtered_stmts(self, lookup_node, node, _stmts, mystmt): def _get_filtered_stmts(self, lookup_node, node, _stmts, mystmt):
"""method used in filter_stmts""" """method used in filter_stmts"""
...@@ -91,18 +77,11 @@ class AssignTypeMixin(object): ...@@ -91,18 +77,11 @@ class AssignTypeMixin(object):
class ParentAssignTypeMixin(AssignTypeMixin): class ParentAssignTypeMixin(AssignTypeMixin):
def assign_type(self):
return self.parent.assign_type()
def ass_type(self): def ass_type(self):
warnings.warn('%s.ass_type() is deprecated and slated for removal ' return self.parent.ass_type()
'in astroid 2.0, use %s.assign_type() instead.'
% (type(self).__name__, type(self).__name__),
PendingDeprecationWarning, stacklevel=2)
return self.assign_type()
class ImportFromMixin(FilterStmtsMixin): class FromImportMixIn(FilterStmtsMixin):
"""MixIn for From and Import Nodes""" """MixIn for From and Import Nodes"""
def _infer_name(self, frame, name): def _infer_name(self, frame, name):
...@@ -125,14 +104,11 @@ class ImportFromMixin(FilterStmtsMixin): ...@@ -125,14 +104,11 @@ class ImportFromMixin(FilterStmtsMixin):
# FIXME: we used to raise InferenceError here, but why ? # FIXME: we used to raise InferenceError here, but why ?
return mymodule return mymodule
try: try:
return mymodule.import_module(modname, level=level, return mymodule.import_module(modname, level=level)
relative_only=level and level >= 1) except AstroidBuildingException:
except exceptions.AstroidBuildingException as ex: raise InferenceError(modname)
if isinstance(ex.args[0], SyntaxError):
raise exceptions.InferenceError(str(ex))
raise exceptions.InferenceError(modname)
except SyntaxError as ex: except SyntaxError as ex:
raise exceptions.InferenceError(str(ex)) raise InferenceError(str(ex))
def real_name(self, asname): def real_name(self, asname):
"""get name from 'as' name""" """get name from 'as' name"""
...@@ -144,4 +120,5 @@ class ImportFromMixin(FilterStmtsMixin): ...@@ -144,4 +120,5 @@ class ImportFromMixin(FilterStmtsMixin):
_asname = name _asname = name
if asname == _asname: if asname == _asname:
return name return name
raise exceptions.NotFoundError(asname) raise NotFoundError(asname)
This diff is collapsed.
This diff is collapsed.
...@@ -24,54 +24,40 @@ on all nodes : ...@@ -24,54 +24,40 @@ on all nodes :
.next_sibling(), returning next sibling statement node .next_sibling(), returning next sibling statement node
.statement(), returning the first parent node marked as statement node .statement(), returning the first parent node marked as statement node
.frame(), returning the first node defining a new local scope (i.e. .frame(), returning the first node defining a new local scope (i.e.
Module, FunctionDef or ClassDef) Module, Function or Class)
.set_local(name, node), define an identifier <name> on the first parent frame, .set_local(name, node), define an identifier <name> on the first parent frame,
with the node defining it. This is used by the astroid builder and should not with the node defining it. This is used by the astroid builder and should not
be used from out there. be used from out there.
on ImportFrom and Import : on From and Import :
.real_name(name), .real_name(name),
""" """
# pylint: disable=unused-import,redefined-builtin # pylint: disable=unused-import
from astroid.node_classes import (
Arguments, AssignAttr, Assert, Assign,
AssignName, AugAssign, Repr, BinOp, BoolOp, Break, Call, Compare,
Comprehension, Const, Continue, Decorators, DelAttr, DelName, Delete,
Dict, Expr, Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, For,
ImportFrom, Attribute, 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,
AsyncFor, Await, AsyncWith,
# Backwards-compatibility aliases
Backquote, Discard, AssName, AssAttr, Getattr, CallFunc, From,
# Node not present in the builtin ast module.
DictUnpack,
)
from astroid.scoped_nodes import (
Module, GeneratorExp, Lambda, DictComp,
ListComp, SetComp, FunctionDef, ClassDef,
AsyncFunctionDef,
# Backwards-compatibility aliases
Class, Function, GenExpr,
)
__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 = ( ALL_NODE_CLASSES = (
AsyncFunctionDef, AsyncFor, AsyncWith, Await, Arguments, AssAttr, Assert, Assign, AssName, AugAssign,
Backquote, BinOp, BoolOp, Break,
Arguments, AssignAttr, Assert, Assign, AssignName, AugAssign, CallFunc, Class, Compare, Comprehension, Const, Continue,
Repr, BinOp, BoolOp, Break,
Call, ClassDef, Compare, Comprehension, Const, Continue,
Decorators, DelAttr, DelName, Delete, Decorators, DelAttr, DelName, Delete,
Dict, DictComp, DictUnpack, Expr, Dict, DictComp, Discard,
Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice,
For, ImportFrom, FunctionDef, For, From, Function,
Attribute, GeneratorExp, Global, Getattr, GenExpr, Global,
If, IfExp, Import, Index, If, IfExp, Import, Index,
Keyword, Keyword,
Lambda, List, ListComp, Lambda, List, ListComp,
...@@ -83,5 +69,6 @@ ALL_NODE_CLASSES = ( ...@@ -83,5 +69,6 @@ ALL_NODE_CLASSES = (
TryExcept, TryFinally, Tuple, TryExcept, TryFinally, Tuple,
UnaryOp, UnaryOp,
While, With, While, With,
Yield, YieldFrom, Yield, YieldFrom
) )
# 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 <http://www.gnu.org/licenses/>.
"""
Inference objects are a way to represent composite AST nodes,
which are used only as inference results, so they can't be found in the
code tree. For instance, inferring the following frozenset use, leads to an
inferred FrozenSet:
CallFunc(func=Name('frozenset'), args=Tuple(...))
"""
import six
from astroid import MANAGER
from astroid.bases import (
BUILTINS, NodeNG, Instance, _infer_stmts,
BoundMethod, _is_property
)
from astroid.decorators import cachedproperty
from astroid.exceptions import (
SuperError, SuperArgumentTypeError,
NotFoundError, MroError
)
from astroid.node_classes import const_factory
from astroid.scoped_nodes import ClassDef, FunctionDef
from astroid.mixins import ParentAssignTypeMixin
class FrozenSet(NodeNG, Instance, ParentAssignTypeMixin):
"""class representing a FrozenSet composite node"""
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.frozenset' % BUILTINS
def itered(self):
return self.elts
def _infer(self, context=None):
yield self
@cachedproperty
def _proxied(self):
builtins = MANAGER.astroid_cache[BUILTINS]
return builtins.getattr('frozenset')[0]
class Super(NodeNG):
"""Proxy class over a super call.
This class offers almost the same behaviour as Python's super,
which is MRO lookups for retrieving attributes from the parents.
The *mro_pointer* is the place in the MRO from where we should
start looking, not counting it. *mro_type* is the object which
provides the MRO, it can be both a type or an instance.
*self_class* is the class where the super call is, while
*scope* is the function where the super call is.
"""
def __init__(self, mro_pointer, mro_type, self_class, scope):
self.type = mro_type
self.mro_pointer = mro_pointer
self._class_based = False
self._self_class = self_class
self._scope = scope
self._model = {
'__thisclass__': self.mro_pointer,
'__self_class__': self._self_class,
'__self__': self.type,
'__class__': self._proxied,
}
def _infer(self, context=None):
yield self
def super_mro(self):
"""Get the MRO which will be used to lookup attributes in this super."""
if not isinstance(self.mro_pointer, ClassDef):
raise SuperArgumentTypeError("The first super argument must be type.")
if isinstance(self.type, ClassDef):
# `super(type, type)`, most likely in a class method.
self._class_based = True
mro_type = self.type
else:
mro_type = getattr(self.type, '_proxied', None)
if not isinstance(mro_type, (Instance, ClassDef)):
raise SuperArgumentTypeError("super(type, obj): obj must be an "
"instance or subtype of type")
if not mro_type.newstyle:
raise SuperError("Unable to call super on old-style classes.")
mro = mro_type.mro()
if self.mro_pointer not in mro:
raise SuperArgumentTypeError("super(type, obj): obj must be an "
"instance or subtype of type")
index = mro.index(self.mro_pointer)
return mro[index + 1:]
@cachedproperty
def _proxied(self):
builtins = MANAGER.astroid_cache[BUILTINS]
return builtins.getattr('super')[0]
def pytype(self):
return '%s.super' % BUILTINS
def display_type(self):
return 'Super of'
@property
def name(self):
"""Get the name of the MRO pointer."""
return self.mro_pointer.name
def igetattr(self, name, context=None):
"""Retrieve the inferred values of the given attribute name."""
local_name = self._model.get(name)
if local_name:
yield local_name
return
try:
mro = self.super_mro()
except (MroError, SuperError) as exc:
# Don't let invalid MROs or invalid super calls
# to leak out as is from this function.
six.raise_from(NotFoundError, exc)
found = False
for cls in mro:
if name not in cls._locals:
continue
found = True
for infered in _infer_stmts([cls[name]], context, frame=self):
if not isinstance(infered, FunctionDef):
yield infered
continue
# We can obtain different descriptors from a super depending
# on what we are accessing and where the super call is.
if infered.type == 'classmethod':
yield BoundMethod(infered, cls)
elif self._scope.type == 'classmethod' and infered.type == 'method':
yield infered
elif self._class_based or infered.type == 'staticmethod':
yield infered
elif _is_property(infered):
# TODO: support other descriptors as well.
for value in infered.infer_call_result(self, context):
yield value
else:
yield BoundMethod(infered, cls)
if not found:
raise NotFoundError(name)
def getattr(self, name, context=None):
return list(self.igetattr(name, context=context))
This diff is collapsed.
...@@ -19,8 +19,9 @@ ...@@ -19,8 +19,9 @@
(build_* functions) or from living object (object_build_* functions) (build_* functions) or from living object (object_build_* functions)
""" """
__docformat__ = "restructuredtext en"
import sys import sys
import os
from os.path import abspath from os.path import abspath
from inspect import (getargspec, isdatadescriptor, isfunction, ismethod, from inspect import (getargspec, isdatadescriptor, isfunction, ismethod,
ismethoddescriptor, isclass, isbuiltin, ismodule) ismethoddescriptor, isclass, isbuiltin, ismodule)
...@@ -34,8 +35,6 @@ from astroid.manager import AstroidManager ...@@ -34,8 +35,6 @@ from astroid.manager import AstroidManager
MANAGER = AstroidManager() MANAGER = AstroidManager()
_CONSTANTS = tuple(CONST_CLS) # the keys of CONST_CLS eg python builtin types _CONSTANTS = tuple(CONST_CLS) # the keys of CONST_CLS eg python builtin types
_JYTHON = os.name == 'java'
_BUILTINS = vars(six.moves.builtins)
def _io_discrepancy(member): def _io_discrepancy(member):
# _io module names itself `io`: http://bugs.python.org/issue18602 # _io module names itself `io`: http://bugs.python.org/issue18602
...@@ -49,18 +48,6 @@ def _attach_local_node(parent, node, name): ...@@ -49,18 +48,6 @@ def _attach_local_node(parent, node, name):
node.name = name # needed by add_local_node node.name = name # needed by add_local_node
parent.add_local_node(node) parent.add_local_node(node)
def _add_dunder_class(func, member):
"""Add a __class__ member to the given func node, if we can determine it."""
python_cls = member.__class__
cls_name = getattr(python_cls, '__name__', None)
if not cls_name:
return
bases = [ancestor.__name__ for ancestor in python_cls.__bases__]
ast_klass = build_class(cls_name, bases, python_cls.__doc__)
func._instance_attrs['__class__'] = [ast_klass]
_marker = object() _marker = object()
def attach_dummy_node(node, name, object=_marker): def attach_dummy_node(node, name, object=_marker):
...@@ -183,7 +170,6 @@ def object_build_methoddescriptor(node, member, localname): ...@@ -183,7 +170,6 @@ def object_build_methoddescriptor(node, member, localname):
# and empty argument list # and empty argument list
func.args.args = None func.args.args = None
node.add_local_node(func, localname) node.add_local_node(func, localname)
_add_dunder_class(func, member)
def _base_class_object_build(node, member, basenames, name=None, localname=None): 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 """create astroid for a living class object, with a given set of base names
...@@ -210,7 +196,7 @@ def _base_class_object_build(node, member, basenames, name=None, localname=None) ...@@ -210,7 +196,7 @@ def _base_class_object_build(node, member, basenames, name=None, localname=None)
valnode.object = obj valnode.object = obj
valnode.parent = klass valnode.parent = klass
valnode.lineno = 1 valnode.lineno = 1
klass._instance_attrs[name] = [valnode] klass.instance_attrs[name] = [valnode]
return klass return klass
...@@ -242,7 +228,7 @@ class InspectBuilder(object): ...@@ -242,7 +228,7 @@ class InspectBuilder(object):
except AttributeError: except AttributeError:
# in jython, java modules have no __doc__ (see #109562) # in jython, java modules have no __doc__ (see #109562)
node = build_module(modname) node = build_module(modname)
node.source_file = path and abspath(path) or path node.file = node.path = path and abspath(path) or path
node.name = modname node.name = modname
MANAGER.cache_module(node) MANAGER.cache_module(node)
node.package = hasattr(module, '__path__') node.package = hasattr(module, '__path__')
...@@ -287,7 +273,7 @@ class InspectBuilder(object): ...@@ -287,7 +273,7 @@ class InspectBuilder(object):
continue continue
if member in self._done: if member in self._done:
class_node = self._done[member] class_node = self._done[member]
if not class_node in node._locals.get(name, ()): if not class_node in node.locals.get(name, ()):
node.add_local_node(class_node, name) node.add_local_node(class_node, name)
else: else:
class_node = object_build_class(node, member, name) class_node = object_build_class(node, member, name)
...@@ -321,8 +307,7 @@ class InspectBuilder(object): ...@@ -321,8 +307,7 @@ class InspectBuilder(object):
traceback.print_exc() traceback.print_exc()
modname = None modname = None
if modname is None: if modname is None:
if (name in ('__new__', '__subclasshook__') if name in ('__new__', '__subclasshook__'):
or (name in _BUILTINS and _JYTHON)):
# Python 2.5.1 (r251:54863, Sep 1 2010, 22:03:14) # Python 2.5.1 (r251:54863, Sep 1 2010, 22:03:14)
# >>> print object.__new__.__module__ # >>> print object.__new__.__module__
# None # None
...@@ -330,13 +315,7 @@ class InspectBuilder(object): ...@@ -330,13 +315,7 @@ class InspectBuilder(object):
else: else:
attach_dummy_node(node, name, member) attach_dummy_node(node, name, member)
return True return True
if {'gtk': 'gtk._gtk'}.get(modname, modname) != self._module.__name__:
real_name = {
'gtk': 'gtk_gtk',
'_io': 'io',
}.get(modname, modname)
if real_name != self._module.__name__:
# check if it sounds valid and then add an import node, else use a # check if it sounds valid and then add an import node, else use a
# dummy node # dummy node
try: try:
...@@ -358,16 +337,13 @@ def _astroid_bootstrapping(astroid_builtin=None): ...@@ -358,16 +337,13 @@ def _astroid_bootstrapping(astroid_builtin=None):
# this boot strapping is necessary since we need the Const nodes to # this boot strapping is necessary since we need the Const nodes to
# inspect_build builtins, and then we can proxy Const # inspect_build builtins, and then we can proxy Const
if astroid_builtin is None: if astroid_builtin is None:
from six.moves import builtins from logilab.common.compat import builtins
astroid_builtin = Astroid_BUILDER.inspect_build(builtins) astroid_builtin = Astroid_BUILDER.inspect_build(builtins)
for cls, node_cls in CONST_CLS.items(): for cls, node_cls in CONST_CLS.items():
if cls is type(None): if cls is type(None):
proxy = build_class('NoneType') proxy = build_class('NoneType')
proxy.parent = astroid_builtin proxy.parent = astroid_builtin
elif cls is type(NotImplemented):
proxy = build_class('NotImplementedType')
proxy.parent = astroid_builtin
else: else:
proxy = astroid_builtin.getattr(cls.__name__)[0] proxy = astroid_builtin.getattr(cls.__name__)[0]
if cls in (dict, list, set, tuple): if cls in (dict, list, set, tuple):
......
This diff is collapsed.
This diff is collapsed.
"""Utility functions for test code that uses astroid ASTs as input.""" """Utility functions for test code that uses astroid ASTs as input."""
import functools import functools
import sys import sys
import textwrap
from astroid import nodes from astroid import nodes
from astroid import builder from astroid import builder
...@@ -13,6 +14,7 @@ _TRANSIENT_FUNCTION = '__' ...@@ -13,6 +14,7 @@ _TRANSIENT_FUNCTION = '__'
# when calling extract_node. # when calling extract_node.
_STATEMENT_SELECTOR = '#@' _STATEMENT_SELECTOR = '#@'
def _extract_expressions(node): def _extract_expressions(node):
"""Find expressions in a call to _TRANSIENT_FUNCTION and extract them. """Find expressions in a call to _TRANSIENT_FUNCTION and extract them.
...@@ -26,7 +28,7 @@ def _extract_expressions(node): ...@@ -26,7 +28,7 @@ def _extract_expressions(node):
:yields: The sequence of wrapped expressions on the modified tree :yields: The sequence of wrapped expressions on the modified tree
expression can be found. expression can be found.
""" """
if (isinstance(node, nodes.Call) if (isinstance(node, nodes.CallFunc)
and isinstance(node.func, nodes.Name) and isinstance(node.func, nodes.Name)
and node.func.name == _TRANSIENT_FUNCTION): and node.func.name == _TRANSIENT_FUNCTION):
real_expr = node.args[0] real_expr = node.args[0]
...@@ -66,7 +68,7 @@ def _find_statement_by_line(node, line): ...@@ -66,7 +68,7 @@ def _find_statement_by_line(node, line):
can be found. can be found.
:rtype: astroid.bases.NodeNG or None :rtype: astroid.bases.NodeNG or None
""" """
if isinstance(node, (nodes.ClassDef, nodes.FunctionDef)): if isinstance(node, (nodes.Class, nodes.Function)):
# This is an inaccuracy in the AST: the nodes that can be # This is an inaccuracy in the AST: the nodes that can be
# decorated do not carry explicit information on which line # decorated do not carry explicit information on which line
# the actual definition (class/def), but .fromline seems to # the actual definition (class/def), but .fromline seems to
...@@ -140,7 +142,7 @@ def extract_node(code, module_name=''): ...@@ -140,7 +142,7 @@ def extract_node(code, module_name=''):
:rtype: astroid.bases.NodeNG, or a list of nodes. :rtype: astroid.bases.NodeNG, or a list of nodes.
""" """
def _extract(node): def _extract(node):
if isinstance(node, nodes.Expr): if isinstance(node, nodes.Discard):
return node.value return node.value
else: else:
return node return node
...@@ -150,7 +152,7 @@ def extract_node(code, module_name=''): ...@@ -150,7 +152,7 @@ def extract_node(code, module_name=''):
if line.strip().endswith(_STATEMENT_SELECTOR): if line.strip().endswith(_STATEMENT_SELECTOR):
requested_lines.append(idx + 1) requested_lines.append(idx + 1)
tree = builder.parse(code, module_name=module_name) tree = build_module(code, module_name=module_name)
extracted = [] extracted = []
if requested_lines: if requested_lines:
for line in requested_lines: for line in requested_lines:
...@@ -169,6 +171,21 @@ def extract_node(code, module_name=''): ...@@ -169,6 +171,21 @@ def extract_node(code, module_name=''):
return extracted 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): def require_version(minver=None, maxver=None):
""" Compare version of python interpreter to the given one. Skip the test """ Compare version of python interpreter to the given one. Skip the test
if older. if older.
......
# 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 <http://www.gnu.org/licenses/>.
import collections
import warnings
class TransformVisitor(object):
"""A visitor for handling transforms.
The standard approach of using it is to call
:meth:`~visit` with an *astroid* module and the class
will take care of the rest, walking the tree and running the
transforms for each encountered node.
"""
def __init__(self):
self.transforms = collections.defaultdict(list)
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
warnings.warn('node %s substituted multiple times' % node)
node = ret
return node
def _visit(self, node):
if hasattr(node, '_astroid_fields'):
for field in node._astroid_fields:
value = getattr(node, field)
visited = self._visit_generic(value)
setattr(node, field, visited)
return self._transform(node)
def _visit_generic(self, node):
if isinstance(node, list):
return [self._visit_generic(child) for child in node]
elif isinstance(node, tuple):
return tuple(self._visit_generic(child) for child in node)
else:
return self._visit(node)
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 visit(self, module):
"""Walk the given astroid *tree* and transform each encountered node
Only the nodes which have transforms registered will actually
be replaced or changed.
"""
module.body = [self._visit(child) for child in module.body]
return self._transform(module)
# 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 <http://www.gnu.org/licenses/>.
#
# The code in this file was originally part of logilab-common, licensed under
# the same license.
import warnings
from astroid import exceptions
def generate_warning(message, warning):
return lambda *args: warnings.warn(message % args, warning, stacklevel=3)
rename_warning = generate_warning(
"%r is deprecated and will be removed in astroid %.1f, use %r instead",
PendingDeprecationWarning)
attribute_to_method_warning = generate_warning(
"%s is deprecated and will be removed in astroid %.1f, use the "
"method '%s()' instead.", PendingDeprecationWarning)
attribute_to_function_warning = generate_warning(
"%s is deprecated and will be removed in astroid %.1f, use the "
"function '%s()' instead.", PendingDeprecationWarning)
method_to_function_warning = generate_warning(
"%s() is deprecated and will be removed in astroid %.1f, use the "
"function '%s()' instead.", PendingDeprecationWarning)
class _Yes(object):
"""Special inference object, which is returned when inference fails."""
def __repr__(self):
return 'YES'
__str__ = __repr__
def __getattribute__(self, name):
if name == 'next':
raise AttributeError('next method should not be called')
if name.startswith('__') and name.endswith('__'):
return super(_Yes, self).__getattribute__(name)
if name == 'accept':
return super(_Yes, self).__getattribute__(name)
return self
def __call__(self, *args, **kwargs):
return self
def accept(self, visitor):
func = getattr(visitor, "visit_yes")
return func(self)
YES = _Yes()
def safe_infer(node, context=None):
"""Return the inferred value for the given node.
Return None if inference failed or if there is some ambiguity (more than
one node has been inferred).
"""
try:
inferit = node.infer(context=context)
value = next(inferit)
except exceptions.InferenceError:
return
try:
next(inferit)
return # None if there is ambiguity on the inferred node
except exceptions.InferenceError:
return # there is some kind of ambiguity
except StopIteration:
return value
This diff is collapsed.
This diff is collapsed.
URL: http://www.logilab.org/project/logilab-common
Version: 0.63.2
License: GPL
License File: LICENSE.txt
Description:
This directory contains the logilab-common module, required for logilab-astng
and pylint.
Local Modifications:
None
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
from warnings import warn
warn('logilab.common.contexts module is deprecated, use logilab.common.shellutils instead',
DeprecationWarning, stacklevel=1)
from logilab.common.shellutils import tempfile, pushd
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment