Commit 862370c6 authored by Mike Frysinger's avatar Mike Frysinger Committed by Commit Bot

pylint: reland upgrade to 1.5.6

** WARNING: please do not revert this CL without checking with vapier@ first ***

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 its deps along the way:
- Update astroid to 1.4.9.
- Drop now unused logilab.common.
- Import lazy_object_proxy 1.3.1.
- Import wrapt 1.10.11.

This should address the issue where some Chromium bots don't have the
lazy_object_proxy/wrapt python modules installed.  These have optional
C modules that we don't compile either as they have Python fallbacks.

Bug: 863669
Change-Id: Iade0e6d89598e2c836ed647996f43db356c43cd0
Reviewed-on: https://chromium-review.googlesource.com/1145485
Commit-Queue: Ned Nguyen <nednguyen@google.com>
Reviewed-by: 's avatarRobbie Iannucci <iannucci@chromium.org>
Reviewed-by: 's avatarJohn Budorick <jbudorick@chromium.org>
parent 40764b07
......@@ -7,9 +7,6 @@
# pygtk.require().
#init-hook=
# Profiled execution.
profile=no
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
......@@ -93,31 +90,53 @@ disable=
logging-not-lazy,
bad-continuation,
anomalous-backslash-in-string,
assigning-non-slot,
bad-context-manager,
bad-indentation,
bad-str-strip-call,
bad-super-call,
bad-whitespace,
cell-var-from-loop,
consider-using-enumerate,
deprecated-lambda,
deprecated-method,
eval-used,
function-redefined,
import-error,
locally-enabled,
misplaced-comparison-constant,
misplaced-bare-raise,
missing-final-newline,
multiple-imports,
no-init,
no-name-in-module,
no-self-argument,
no-self-use,
not-an-iterable,
not-callable,
old-style-class,
protected-access,
redefined-variable-type,
simplifiable-if-statement,
singleton-comparison,
superfluous-parens,
super-on-old-class,
too-many-boolean-expressions,
too-many-function-args,
too-many-nested-blocks,
trailing-whitespace,
undefined-variable,
ungrouped-imports,
unnecessary-semicolon,
unneeded-not,
unpacking-non-sequence,
unsubscriptable-object,
unsupported-membership-test,
unused-import,
useless-else-on-loop
useless-else-on-loop,
using-constant-test,
wrong-import-order,
wrong-import-position,
[REPORTS]
......@@ -142,10 +161,6 @@ reports=no
# (RP0004).
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]
......@@ -171,10 +186,6 @@ ignore-mixin-members=yes
# (useful for classes with attributes dynamically set).
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
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
......@@ -215,9 +226,6 @@ indent-string=' '
[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
bad-functions=map,filter,apply,input
......@@ -296,10 +304,6 @@ max-public-methods=20
[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.
defining-attr-methods=__init__,__new__,setUp
......
URL: http://www.logilab.org/
Description:
This directory contains the logilab-astng and logilab-common modules. See
the individual README.chromium files for details.
This directory contains modules that pylint needs.
See the individual README.chromium files for details.
Local Modifications:
None
URL: https://github.com/PyCQA/astroid
Version: 1.3.8
URL: https://pypi.org/project/astroid/#files
Version: 1.4.9
License: GPL
License File: LICENSE.txt
......
......@@ -58,13 +58,15 @@ from astroid import inference
# more stuff available
from astroid import raw_building
from astroid.bases import YES, Instance, BoundMethod, UnboundMethod
from astroid.bases import Instance, BoundMethod, UnboundMethod
from astroid.node_classes import are_exclusive, unpack_infer
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
# accessible from astroid package
from astroid.manager import AstroidManager, Project
from astroid.manager import AstroidManager
MANAGER = AstroidManager()
del AstroidManager
......@@ -100,7 +102,7 @@ def inference_tip(infer_function):
.. sourcecode:: python
MANAGER.register_transform(CallFunc, inference_tip(infer_named_tuple),
MANAGER.register_transform(Call, inference_tip(infer_named_tuple),
predicate)
"""
def transform(node, infer_function=infer_function):
......@@ -112,8 +114,11 @@ def inference_tip(infer_function):
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
for name, objs in extension_module._locals.items():
node._locals[name] = objs
for obj in objs:
if obj.parent is extension_module:
obj.parent = node
manager.register_transform(Module, transform, lambda n: n.name == module_name)
......
......@@ -20,17 +20,17 @@ distname = 'astroid'
modname = 'astroid'
numversion = (1, 3, 8)
numversion = (1, 4, 9)
version = '.'.join([str(num) for num in numversion])
install_requires = ['logilab-common>=0.63.0', 'six']
install_requires = ['six', 'lazy_object_proxy', 'wrapt']
license = 'LGPL'
author = 'Logilab'
author_email = 'pylint-dev@lists.logilab.org'
author = 'Python Code Quality Authority'
author_email = 'code-quality@python.org'
mailinglist = "mailto://%s" % author_email
web = 'http://bitbucket.org/logilab/astroid'
web = 'https://github.com/PyCQA/astroid'
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,10 @@
* :func:`dump` function return an internal representation of nodes found
in the tree, useful for debugging or understanding the tree structure
"""
import sys
import six
INDENT = ' ' # 4 spaces ; keep indentation variable
......@@ -89,9 +90,9 @@ class AsStringVisitor(object):
"""return an astroid.Function node as string"""
return node.format_args()
def visit_assattr(self, node):
def visit_assignattr(self, node):
"""return an astroid.AssAttr node as string"""
return self.visit_getattr(node)
return self.visit_attribute(node)
def visit_assert(self, node):
"""return an astroid.Assert node as string"""
......@@ -100,7 +101,7 @@ class AsStringVisitor(object):
node.fail.accept(self))
return 'assert %s' % node.test.accept(self)
def visit_assname(self, node):
def visit_assignname(self, node):
"""return an astroid.AssName node as string"""
return node.name
......@@ -113,8 +114,8 @@ class AsStringVisitor(object):
"""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"""
def visit_repr(self, node):
"""return an astroid.Repr node as string"""
return '`%s`' % node.value.accept(self)
def visit_binop(self, node):
......@@ -130,18 +131,20 @@ class AsStringVisitor(object):
"""return an astroid.Break node as string"""
return 'break'
def visit_callfunc(self, node):
"""return an astroid.CallFunc node as string"""
def visit_call(self, node):
"""return an astroid.Call 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))
if node.keywords:
keywords = [kwarg.accept(self) for kwarg in node.keywords]
else:
keywords = []
args.extend(keywords)
return '%s(%s)' % (expr_str, ', '.join(args))
def visit_class(self, node):
"""return an astroid.Class node as string"""
def visit_classdef(self, node):
"""return an astroid.ClassDef 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:
......@@ -186,7 +189,7 @@ class AsStringVisitor(object):
def visit_delattr(self, node):
"""return an astroid.DelAttr node as string"""
return self.visit_getattr(node)
return self.visit_attribute(node)
def visit_delname(self, node):
"""return an astroid.DelName node as string"""
......@@ -198,16 +201,27 @@ class AsStringVisitor(object):
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])
return '{%s}' % ', '.join(self._visit_dict(node))
def _visit_dict(self, node):
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):
"""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):
def visit_expr(self, node):
"""return an astroid.Discard node as string"""
return node.value.accept(self)
......@@ -258,24 +272,33 @@ class AsStringVisitor(object):
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"""
def visit_importfrom(self, node):
"""return an astroid.ImportFrom node as string"""
return 'from %s import %s' % ('.' * (node.level or 0) + node.modname,
_import_string(node.names))
def visit_function(self, node):
def visit_functiondef(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_annotation = ''
if six.PY3 and node.returns:
return_annotation = '->' + node.returns.as_string()
trailer = return_annotation + ":"
else:
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),
' '.join([n.accept(self) for n in node.generators]))
def visit_getattr(self, node):
def visit_attribute(self, node):
"""return an astroid.Getattr node as string"""
return '%s.%s' % (node.expr.accept(self), node.attrname)
......@@ -302,6 +325,8 @@ class AsStringVisitor(object):
def visit_keyword(self, node):
"""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))
def visit_lambda(self, node):
......@@ -438,6 +463,22 @@ class AsStringVisitor(object):
else:
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):
"""AsStringVisitor3k overwrites some AsStringVisitor methods"""
......@@ -466,10 +507,6 @@ class AsStringVisitor3k(AsStringVisitor):
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 ""
......@@ -479,6 +516,19 @@ class AsStringVisitor3k(AsStringVisitor):
else:
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):
"""return a list of (name, asname) formatted as a string"""
......@@ -496,4 +546,3 @@ if sys.version_info >= (3, 0):
# this visitor is stateless, thus it can be reused
to_code = AsStringVisitor()
This diff is collapsed.
......@@ -7,9 +7,11 @@ from textwrap import dedent
import six
from astroid import (MANAGER, UseInferenceDefault,
inference_tip, YES, InferenceError, UnresolvableName)
from astroid import arguments
from astroid import nodes
from astroid import objects
from astroid.builder import AstroidBuilder
from astroid import util
def _extend_str(class_node, rvalue):
"""function to extend builtin str/unicode class"""
......@@ -51,7 +53,7 @@ def _extend_str(class_node, rvalue):
def rstrip(self, chars=None):
return {rvalue}
def rjust(self, width, fillchar=None):
return {rvalue}
return {rvalue}
def center(self, width, fillchar=None):
return {rvalue}
def ljust(self, width, fillchar=None):
......@@ -60,7 +62,7 @@ def _extend_str(class_node, rvalue):
code = code.format(rvalue=rvalue)
fake = AstroidBuilder(MANAGER).string_build(code)['whatever']
for method in fake.mymethods():
class_node.locals[method.name] = [method]
class_node._locals[method.name] = [method]
method.parent = class_node
def extend_builtins(class_transforms):
......@@ -86,12 +88,17 @@ def register_builtin_transform(transform, builtin_name):
def _transform_wrapper(node, context=None):
result = transform(node, context=context)
if result:
result.parent = node
if not result.parent:
# 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.col_offset = node.col_offset
return iter([result])
MANAGER.register_transform(nodes.CallFunc,
MANAGER.register_transform(nodes.Call,
inference_tip(_transform_wrapper),
lambda n: (isinstance(n.func, nodes.Name) and
n.func.name == builtin_name))
......@@ -108,13 +115,13 @@ def _generic_inference(node, context, node_type, transform):
transformed = transform(arg)
if not transformed:
try:
infered = next(arg.infer(context=context))
inferred = next(arg.infer(context=context))
except (InferenceError, StopIteration):
raise UseInferenceDefault()
if infered is YES:
if inferred is util.YES:
raise UseInferenceDefault()
transformed = transform(infered)
if not transformed or transformed is YES:
transformed = transform(inferred)
if not transformed or transformed is util.YES:
raise UseInferenceDefault()
return transformed
......@@ -172,19 +179,25 @@ infer_set = partial(
iterables=(nodes.List, nodes.Tuple),
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):
is_iterable = lambda n: isinstance(n,
(nodes.List, nodes.Tuple, nodes.Set))
try:
infered = next(arg.infer(context))
inferred = next(arg.infer(context))
except (InferenceError, UnresolvableName):
raise UseInferenceDefault()
if isinstance(infered, nodes.Dict):
items = infered.items
elif is_iterable(infered):
if isinstance(inferred, nodes.Dict):
items = inferred.items
elif is_iterable(inferred):
items = []
for elt in infered.elts:
for elt in inferred.elts:
# If an item is not a pair of two items,
# then fallback to the default inference.
# Also, take in consideration only hashable items,
......@@ -213,24 +226,28 @@ def infer_dict(node, context=None):
* dict(mapping, **kwargs)
* dict(**kwargs)
If a case can't be infered, we'll fallback to default inference.
If a case can't be inferred, 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:
call = arguments.CallSite.from_call(node)
if call.has_invalid_arguments() or call.has_invalid_keywords():
raise UseInferenceDefault
args = call.positional_arguments
kwargs = list(call.keyword_arguments.items())
if not args and not kwargs:
# dict()
return nodes.Dict()
elif has_keywords(node.args) and node.args:
elif kwargs and not 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:])):
items = [(nodes.Const(key), value) for key, value in kwargs]
elif len(args) == 1 and kwargs:
# 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:]]
elts = _get_elts(args[0], context)
keys = [(nodes.Const(key), value) for key, value in kwargs]
items = elts + keys
elif len(node.args) == 1:
items = _get_elts(node.args[0], context)
elif len(args) == 1:
items = _get_elts(args[0], context)
else:
raise UseInferenceDefault()
......@@ -238,8 +255,82 @@ def infer_dict(node, context=None):
empty.items = items
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
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_set, 'set')
register_builtin_transform(infer_list, 'list')
register_builtin_transform(infer_dict, 'dict')
register_builtin_transform(infer_frozenset, 'frozenset')
"""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)
......@@ -7,8 +7,9 @@ import inspect
import itertools
import sys
import re
import warnings
from astroid import MANAGER, AstroidBuildingException
from astroid import MANAGER, AstroidBuildingException, nodes
from astroid.builder import AstroidBuilder
......@@ -46,13 +47,13 @@ def _gi_build_stub(parent):
elif (inspect.ismethod(obj) or
inspect.ismethoddescriptor(obj)):
methods[name] = obj
elif type(obj) in [int, str]:
constants[name] = obj
elif (str(obj).startswith("<flags") or
str(obj).startswith("<enum ") or
str(obj).startswith("<GType ") or
inspect.isdatadescriptor(obj)):
constants[name] = 0
elif isinstance(obj, (int, str)):
constants[name] = obj
elif callable(obj):
# Fall back to a function for anything callable
functions[name] = obj
......@@ -73,7 +74,7 @@ def _gi_build_stub(parent):
val = constants[name]
strval = str(val)
if type(val) is str:
if isinstance(val, str):
strval = '"%s"' % str(val).replace("\\", "\\\\")
ret += "%s = %s\n" % (name, strval)
......@@ -82,7 +83,6 @@ def _gi_build_stub(parent):
if functions:
ret += "# %s functions\n\n" % parent.__name__
for name in sorted(functions):
func = functions[name]
ret += "def %s(*args, **kwargs):\n" % name
ret += " pass\n"
......@@ -91,7 +91,6 @@ def _gi_build_stub(parent):
if methods:
ret += "# %s methods\n\n" % parent.__name__
for name in sorted(methods):
func = methods[name]
ret += "def %s(self, *args, **kwargs):\n" % name
ret += " pass\n"
......@@ -135,7 +134,16 @@ def _import_gi_module(modname):
for m in itertools.chain(modnames, optional_modnames):
try:
__import__(m)
modcode += _gi_build_stub(sys.modules[m])
with warnings.catch_warnings():
# 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:
if m not in optional_modnames:
raise
......@@ -150,6 +158,38 @@ def _import_gi_module(modname):
raise AstroidBuildingException('Failed to import module %r' % modname)
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
MANAGER.register_failed_import_hook(_import_gi_module)
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_transform(nodes.Call, _register_require_version, _looks_like_require_version)
......@@ -48,11 +48,14 @@ def _nose_tools_functions():
if method.name.startswith('assert') and '_' not in method.name:
pep8_name = _pep8(method.name)
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):
for method_name, method in _nose_tools_functions():
node.locals[method_name] = [method]
node._locals[method_name] = [method]
def _nose_tools_trivial_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 pytest."""
from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder
def pytest_transform():
return AstroidBuilder(MANAGER).string_build('''
try:
import _pytest.mark
import _pytest.recwarn
import _pytest.runner
import _pytest.python
except ImportError:
pass
else:
deprecated_call = _pytest.recwarn.deprecated_call
exit = _pytest.runner.exit
fail = _pytest.runner.fail
fixture = _pytest.python.fixture
importorskip = _pytest.runner.importorskip
mark = _pytest.mark.MarkGenerator()
raises = _pytest.python.raises
skip = _pytest.runner.skip
yield_fixture = _pytest.python.yield_fixture
''')
register_module_extender(MANAGER, 'pytest', pytest_transform)
register_module_extender(MANAGER, 'py.test', pytest_transform)
"""Astroid hooks for pytest."""
from __future__ import absolute_import
from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder
def pytest_transform():
return AstroidBuilder(MANAGER).string_build('''
try:
import _pytest.mark
import _pytest.recwarn
import _pytest.runner
import _pytest.python
import _pytest.skipping
import _pytest.assertion
except ImportError:
pass
else:
deprecated_call = _pytest.recwarn.deprecated_call
warns = _pytest.recwarn.warns
exit = _pytest.runner.exit
fail = _pytest.runner.fail
skip = _pytest.runner.skip
importorskip = _pytest.runner.importorskip
xfail = _pytest.skipping.xfail
mark = _pytest.mark.MarkGenerator()
raises = _pytest.python.raises
# 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 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
......@@ -23,7 +23,12 @@ from textwrap import dedent
from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder
from astroid.exceptions import AstroidBuildingException
from astroid.exceptions import AstroidBuildingException, InferenceError
from astroid import nodes
SIX_ADD_METACLASS = 'six.add_metaclass'
def _indent(text, prefix, predicate=None):
"""Adds 'prefix' to the beginning of selected lines in 'text'.
......@@ -254,8 +259,30 @@ def _six_fail_hook(modname):
module.name = 'six.moves'
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, 'requests.packages.urllib3.packages.six',
six_moves_transform)
MANAGER.register_failed_import_hook(_six_fail_hook)
MANAGER.register_transform(nodes.ClassDef, transform_six_add_metaclass)
"""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)
"""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)
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,6 +30,26 @@ class AstroidBuildingException(AstroidError):
class ResolveError(AstroidError):
"""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):
"""raised when we are unable to resolve a name"""
......
This diff is collapsed.
This diff is collapsed.
......@@ -18,16 +18,16 @@
"""This module contains some mixins for the different nodes.
"""
from logilab.common.decorators import cachedproperty
import warnings
from astroid.exceptions import (AstroidBuildingException, InferenceError,
NotFoundError)
from astroid import decorators
from astroid import exceptions
class BlockRangeMixIn(object):
"""override block range """
@cachedproperty
@decorators.cachedproperty
def blockstart_tolineno(self):
return self.lineno
......@@ -55,15 +55,29 @@ class FilterStmtsMixin(object):
return [node], True
return _stmts, False
def ass_type(self):
def assign_type(self):
return self
def ass_type(self):
warnings.warn('%s.ass_type() is deprecated and slated for removal '
'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):
def ass_type(self):
def assign_type(self):
return self
def ass_type(self):
warnings.warn('%s.ass_type() is deprecated and slated for removal '
'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):
"""method used in filter_stmts"""
if self is mystmt:
......@@ -77,11 +91,18 @@ class AssignTypeMixin(object):
class ParentAssignTypeMixin(AssignTypeMixin):
def assign_type(self):
return self.parent.assign_type()
def ass_type(self):
return self.parent.ass_type()
warnings.warn('%s.ass_type() is deprecated and slated for removal '
'in astroid 2.0, use %s.assign_type() instead.'
% (type(self).__name__, type(self).__name__),
PendingDeprecationWarning, stacklevel=2)
return self.assign_type()
class FromImportMixIn(FilterStmtsMixin):
class ImportFromMixin(FilterStmtsMixin):
"""MixIn for From and Import Nodes"""
def _infer_name(self, frame, name):
......@@ -104,11 +125,14 @@ class FromImportMixIn(FilterStmtsMixin):
# FIXME: we used to raise InferenceError here, but why ?
return mymodule
try:
return mymodule.import_module(modname, level=level)
except AstroidBuildingException:
raise InferenceError(modname)
return mymodule.import_module(modname, level=level,
relative_only=level and level >= 1)
except exceptions.AstroidBuildingException as ex:
if isinstance(ex.args[0], SyntaxError):
raise exceptions.InferenceError(str(ex))
raise exceptions.InferenceError(modname)
except SyntaxError as ex:
raise InferenceError(str(ex))
raise exceptions.InferenceError(str(ex))
def real_name(self, asname):
"""get name from 'as' name"""
......@@ -120,5 +144,4 @@ class FromImportMixIn(FilterStmtsMixin):
_asname = name
if asname == _asname:
return name
raise NotFoundError(asname)
raise exceptions.NotFoundError(asname)
This diff is collapsed.
This diff is collapsed.
......@@ -24,40 +24,54 @@ on all nodes :
.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)
Module, FunctionDef or ClassDef)
.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
be used from out there.
on From and Import :
on ImportFrom and Import :
.real_name(name),
"""
# pylint: disable=unused-import
# pylint: disable=unused-import,redefined-builtin
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 = (
Arguments, AssAttr, Assert, Assign, AssName, AugAssign,
Backquote, BinOp, BoolOp, Break,
CallFunc, Class, Compare, Comprehension, Const, Continue,
AsyncFunctionDef, AsyncFor, AsyncWith, Await,
Arguments, AssignAttr, Assert, Assign, AssignName, AugAssign,
Repr, BinOp, BoolOp, Break,
Call, ClassDef, Compare, Comprehension, Const, Continue,
Decorators, DelAttr, DelName, Delete,
Dict, DictComp, Discard,
Dict, DictComp, DictUnpack, Expr,
Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice,
For, From, Function,
Getattr, GenExpr, Global,
For, ImportFrom, FunctionDef,
Attribute, GeneratorExp, Global,
If, IfExp, Import, Index,
Keyword,
Lambda, List, ListComp,
......@@ -69,6 +83,5 @@ ALL_NODE_CLASSES = (
TryExcept, TryFinally, Tuple,
UnaryOp,
While, With,
Yield, YieldFrom
Yield, YieldFrom,
)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
"""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
......@@ -14,7 +13,6 @@ _TRANSIENT_FUNCTION = '__'
# when calling extract_node.
_STATEMENT_SELECTOR = '#@'
def _extract_expressions(node):
"""Find expressions in a call to _TRANSIENT_FUNCTION and extract them.
......@@ -28,7 +26,7 @@ def _extract_expressions(node):
:yields: The sequence of wrapped expressions on the modified tree
expression can be found.
"""
if (isinstance(node, nodes.CallFunc)
if (isinstance(node, nodes.Call)
and isinstance(node.func, nodes.Name)
and node.func.name == _TRANSIENT_FUNCTION):
real_expr = node.args[0]
......@@ -68,7 +66,7 @@ def _find_statement_by_line(node, line):
can be found.
:rtype: astroid.bases.NodeNG or None
"""
if isinstance(node, (nodes.Class, nodes.Function)):
if isinstance(node, (nodes.ClassDef, nodes.FunctionDef)):
# 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
......@@ -142,7 +140,7 @@ def extract_node(code, module_name=''):
:rtype: astroid.bases.NodeNG, or a list of nodes.
"""
def _extract(node):
if isinstance(node, nodes.Discard):
if isinstance(node, nodes.Expr):
return node.value
else:
return node
......@@ -152,7 +150,7 @@ def extract_node(code, module_name=''):
if line.strip().endswith(_STATEMENT_SELECTOR):
requested_lines.append(idx + 1)
tree = build_module(code, module_name=module_name)
tree = builder.parse(code, module_name=module_name)
extracted = []
if requested_lines:
for line in requested_lines:
......@@ -171,21 +169,6 @@ def extract_node(code, module_name=''):
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.
......
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.
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.
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