summaryrefslogtreecommitdiff
path: root/checkers/classes.py
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2014-04-09 11:24:43 +0300
committercpopa <devnull@localhost>2014-04-09 11:24:43 +0300
commitf45cab1b0f8541d6ff2fe39b72090ad9e6613c0e (patch)
treea33b02af8e73b7ac4a73c16a692cb0d90df1378c /checkers/classes.py
parenta819a9485a94769a2315b0dc742849298c191d0d (diff)
parentf6b867557013eb562a01bc5d025ab065edc778f6 (diff)
downloadpylint-f45cab1b0f8541d6ff2fe39b72090ad9e6613c0e.tar.gz
Merge with default.
Diffstat (limited to 'checkers/classes.py')
-rw-r--r--checkers/classes.py54
1 files changed, 53 insertions, 1 deletions
diff --git a/checkers/classes.py b/checkers/classes.py
index af64a44..8242162 100644
--- a/checkers/classes.py
+++ b/checkers/classes.py
@@ -156,7 +156,15 @@ MSGS = {
'bad-context-manager',
'Used when the __exit__ special method, belonging to a \
context manager, does not accept 3 arguments \
- (type, value, traceback).')
+ (type, value, traceback).'),
+ 'E0236': ('Invalid object %r in __slots__, must contain '
+ 'only non empty strings',
+ 'invalid-slots-object',
+ 'Used when an invalid (non-string) object occurs in __slots__.'),
+ 'E0238': ('Invalid __slots__ object',
+ 'invalid-slots',
+ 'Used when an invalid __slots__ is found in class. '
+ 'Only a string, an iterable or a sequence is permitted.')
}
@@ -240,6 +248,7 @@ a metaclass class method.'}
node.local_attr('__init__')
except astroid.NotFoundError:
self.add_message('W0232', args=node, node=node)
+ self._check_slots(node)
@check_messages('E0203', 'W0201')
def leave_class(self, cnode):
@@ -333,6 +342,49 @@ a metaclass class method.'}
elif node.name == '__exit__':
self._check_exit(node)
+ def _check_slots(self, node):
+ if '__slots__' not in node.locals:
+ return
+ for slots in node.igetattr('__slots__'):
+ # check if __slots__ is a valid type
+ for meth in ('__iter__', '__getitem__'):
+ try:
+ slots.getattr(meth)
+ break
+ except astroid.NotFoundError:
+ continue
+ else:
+ self.add_message('invalid-slots', node=node)
+ continue
+
+ if isinstance(slots, astroid.Const):
+ # a string, ignore the following checks
+ continue
+ if not hasattr(slots, 'itered'):
+ # we can't obtain the values, maybe a .deque?
+ continue
+
+ if isinstance(slots, astroid.Dict):
+ values = [item[0] for item in slots.items]
+ else:
+ values = slots.itered()
+ if values is YES:
+ return
+
+ for elt in values:
+ if elt is YES:
+ continue
+ if (not isinstance(elt, astroid.Const) or
+ not isinstance(elt.value, str)):
+ self.add_message('invalid-slots-object',
+ args=elt.as_string(),
+ node=elt)
+ continue
+ if not elt.value:
+ self.add_message('invalid-slots-object',
+ args=elt.as_string(),
+ node=elt)
+
def _check_iter(self, node):
try:
infered = node.infer_call_result(node)