| Index: third_party/pylint/checkers/typecheck.py
|
| diff --git a/third_party/pylint/checkers/typecheck.py b/third_party/pylint/checkers/typecheck.py
|
| index fb8f3c6e769c5217992bb7d82e4e5fb2d0dd1368..10b9f8669fb9353ab9e4766e5174a6ef5a257078 100644
|
| --- a/third_party/pylint/checkers/typecheck.py
|
| +++ b/third_party/pylint/checkers/typecheck.py
|
| @@ -23,23 +23,21 @@ import astroid
|
| from astroid import InferenceError, NotFoundError, YES, Instance
|
| from astroid.bases import BUILTINS
|
|
|
| -from pylint.interfaces import IAstroidChecker
|
| +from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE
|
| from pylint.checkers import BaseChecker
|
| -from pylint.checkers.utils import safe_infer, is_super, check_messages
|
| +from pylint.checkers.utils import (
|
| + safe_infer, is_super,
|
| + check_messages, decorated_with_property)
|
|
|
| MSGS = {
|
| 'E1101': ('%s %r has no %r member',
|
| 'no-member',
|
| - 'Used when a variable is accessed for an unexistent member.'),
|
| + 'Used when a variable is accessed for an unexistent member.',
|
| + {'old_names': [('E1103', 'maybe-no-member')]}),
|
| 'E1102': ('%s is not callable',
|
| 'not-callable',
|
| 'Used when an object being called has been inferred to a non \
|
| callable object'),
|
| - 'E1103': ('%s %r has no %r member (but some types could not be inferred)',
|
| - 'maybe-no-member',
|
| - 'Used when a variable is accessed for an unexistent member, but \
|
| - astroid was not able to interpret all possible types of this \
|
| - variable.'),
|
| 'E1111': ('Assigning to function call which doesn\'t return',
|
| 'assignment-from-no-return',
|
| 'Used when an assignment is done on a function call but the \
|
| @@ -56,11 +54,6 @@ MSGS = {
|
| 'too-many-function-args',
|
| 'Used when a function call passes too many positional \
|
| arguments.'),
|
| - 'E1122': ('Duplicate keyword argument %r in %s call',
|
| - 'duplicate-keyword-arg',
|
| - 'Used when a function call passes the same keyword argument \
|
| - multiple times.',
|
| - {'maxversion': (2, 6)}),
|
| 'E1123': ('Unexpected keyword argument %r in %s call',
|
| 'unexpected-keyword-arg',
|
| 'Used when a function call passes a keyword argument that \
|
| @@ -192,7 +185,7 @@ accessed. Python regular expressions are accepted.'}
|
| def visit_delattr(self, node):
|
| self.visit_getattr(node)
|
|
|
| - @check_messages('no-member', 'maybe-no-member')
|
| + @check_messages('no-member')
|
| def visit_getattr(self, node):
|
| """check that the accessed attribute exists
|
|
|
| @@ -254,6 +247,20 @@ accessed. Python regular expressions are accepted.'}
|
| # explicit skipping of module member access
|
| if owner.root().name in self.config.ignored_modules:
|
| continue
|
| + if isinstance(owner, astroid.Class):
|
| + # Look up in the metaclass only if the owner is itself
|
| + # a class.
|
| + # TODO: getattr doesn't return by default members
|
| + # from the metaclass, because handling various cases
|
| + # of methods accessible from the metaclass itself
|
| + # and/or subclasses only is too complicated for little to
|
| + # no benefit.
|
| + metaclass = owner.metaclass()
|
| + try:
|
| + if metaclass and metaclass.getattr(node.attrname):
|
| + continue
|
| + except NotFoundError:
|
| + pass
|
| missingattr.add((owner, name))
|
| continue
|
| # stop on the first found
|
| @@ -270,13 +277,11 @@ accessed. Python regular expressions are accepted.'}
|
| if actual in done:
|
| continue
|
| done.add(actual)
|
| - if inference_failure:
|
| - msgid = 'maybe-no-member'
|
| - else:
|
| - msgid = 'no-member'
|
| - self.add_message(msgid, node=node,
|
| + confidence = INFERENCE if not inference_failure else INFERENCE_FAILURE
|
| + self.add_message('no-member', node=node,
|
| args=(owner.display_type(), name,
|
| - node.attrname))
|
| + node.attrname),
|
| + confidence=confidence)
|
|
|
| @check_messages('assignment-from-no-return', 'assignment-from-none')
|
| def visit_assign(self, node):
|
| @@ -333,43 +338,17 @@ accessed. Python regular expressions are accepted.'}
|
| except astroid.NotFoundError:
|
| return
|
|
|
| - stop_checking = False
|
| for attr in attrs:
|
| if attr is astroid.YES:
|
| continue
|
| - if stop_checking:
|
| - break
|
| if not isinstance(attr, astroid.Function):
|
| continue
|
|
|
| # Decorated, see if it is decorated with a property
|
| - if not attr.decorators:
|
| - continue
|
| - for decorator in attr.decorators.nodes:
|
| - if not isinstance(decorator, astroid.Name):
|
| - continue
|
| - try:
|
| - for infered in decorator.infer():
|
| - property_like = False
|
| - if isinstance(infered, astroid.Class):
|
| - if (infered.root().name == BUILTINS and
|
| - infered.name == 'property'):
|
| - property_like = True
|
| - else:
|
| - for ancestor in infered.ancestors():
|
| - if (ancestor.name == 'property' and
|
| - ancestor.root().name == BUILTINS):
|
| - property_like = True
|
| - break
|
| - if property_like:
|
| - self.add_message('not-callable', node=node,
|
| - args=node.func.as_string())
|
| - stop_checking = True
|
| - break
|
| - except InferenceError:
|
| - pass
|
| - if stop_checking:
|
| - break
|
| + if decorated_with_property(attr):
|
| + self.add_message('not-callable', node=node,
|
| + args=node.func.as_string())
|
| + break
|
|
|
| @check_messages(*(list(MSGS.keys())))
|
| def visit_callfunc(self, node):
|
| @@ -383,11 +362,7 @@ accessed. Python regular expressions are accepted.'}
|
| num_positional_args = 0
|
| for arg in node.args:
|
| if isinstance(arg, astroid.Keyword):
|
| - keyword = arg.arg
|
| - if keyword in keyword_args:
|
| - self.add_message('duplicate-keyword-arg', node=node,
|
| - args=(keyword, 'function'))
|
| - keyword_args.add(keyword)
|
| + keyword_args.add(arg.arg)
|
| else:
|
| num_positional_args += 1
|
|
|
| @@ -549,7 +524,6 @@ accessed. Python regular expressions are accepted.'}
|
| # slice or instances with __index__.
|
|
|
| parent_type = safe_infer(node.parent.value)
|
| -
|
| if not isinstance(parent_type, (astroid.Class, astroid.Instance)):
|
| return
|
|
|
| @@ -578,13 +552,10 @@ accessed. Python regular expressions are accepted.'}
|
|
|
| if not isinstance(itemmethod, astroid.Function):
|
| return
|
| -
|
| if itemmethod.root().name != BUILTINS:
|
| return
|
| -
|
| if not itemmethod.parent:
|
| return
|
| -
|
| if itemmethod.parent.name not in SEQUENCE_TYPES:
|
| return
|
|
|
| @@ -595,7 +566,6 @@ accessed. Python regular expressions are accepted.'}
|
| index_type = node
|
| else:
|
| index_type = safe_infer(node)
|
| -
|
| if index_type is None or index_type is astroid.YES:
|
| return
|
|
|
| @@ -607,7 +577,6 @@ accessed. Python regular expressions are accepted.'}
|
| elif isinstance(index_type, astroid.Instance):
|
| if index_type.pytype() in (BUILTINS + '.int', BUILTINS + '.slice'):
|
| return
|
| -
|
| try:
|
| index_type.getattr('__index__')
|
| return
|
| @@ -625,7 +594,6 @@ accessed. Python regular expressions are accepted.'}
|
| continue
|
|
|
| index_type = safe_infer(index)
|
| -
|
| if index_type is None or index_type is astroid.YES:
|
| continue
|
|
|
|
|