From 9dead651a8f6394ae6c56956cceee4ebc8ad3c58 Mon Sep 17 00:00:00 2001 From: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com> Date: Fri, 12 Aug 2022 01:45:35 +0200 Subject: Fix crash when a type-annotated `__slots__` with no value is declared. (#7285) * Fix crash when a type-annotated `__slots__` with no value is declared. Closes #7280 --- doc/whatsnew/fragments/7280.other | 3 +++ pylint/checkers/classes/class_checker.py | 5 +++-- tests/functional/s/slots_checks.py | 23 +++++++++++++++++++++++ tests/functional/s/slots_checks.txt | 28 +++++++++++++++------------- 4 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 doc/whatsnew/fragments/7280.other diff --git a/doc/whatsnew/fragments/7280.other b/doc/whatsnew/fragments/7280.other new file mode 100644 index 000000000..84cac7c8f --- /dev/null +++ b/doc/whatsnew/fragments/7280.other @@ -0,0 +1,3 @@ +Fix crash when a type-annotated `__slots__` with no value is declared. + +Closes #7280 diff --git a/pylint/checkers/classes/class_checker.py b/pylint/checkers/classes/class_checker.py index 1fb644466..b48836089 100644 --- a/pylint/checkers/classes/class_checker.py +++ b/pylint/checkers/classes/class_checker.py @@ -1396,7 +1396,8 @@ a metaclass class method.", def _check_slots(self, node: nodes.ClassDef) -> None: if "__slots__" not in node.locals: return - for slots in node.igetattr("__slots__"): + + for slots in node.ilookup("__slots__"): # check if __slots__ is a valid type if slots is astroid.Uninferable: continue @@ -1417,7 +1418,7 @@ a metaclass class method.", else: values = slots.itered() if values is astroid.Uninferable: - return + continue for elt in values: try: self._check_slots_elt(elt, node) diff --git a/tests/functional/s/slots_checks.py b/tests/functional/s/slots_checks.py index a465ef545..2cae34acd 100644 --- a/tests/functional/s/slots_checks.py +++ b/tests/functional/s/slots_checks.py @@ -33,6 +33,18 @@ class FifthGood(object): class SixthGood(object): __slots__ = {"a": "b", "c": "d"} +class SeventhGood: + """type-annotated __slots__ with no value""" + __slots__: str + +class EigthGood: + """Multiple __slots__ declared in the class""" + x = 1 + if x: + __slots__: str + else: + __slots__ = ("y",) + class Bad(object): # [invalid-slots] __slots__ = list @@ -63,6 +75,17 @@ class NinthBad(object): class TenthBad(object): __slots__ = [1 + 2 + 3] # [invalid-slots-object] +class EleventhBad: # [invalid-slots] + __slots__ = None + +class TwelfthBad: # [invalid-slots] + """One valid & one invalid __slots__ value""" + x = 1 + if x: + __slots__ = ("y",) + else: + __slots__ = None + class PotentiallyGood(object): __slots__ = func() diff --git a/tests/functional/s/slots_checks.txt b/tests/functional/s/slots_checks.txt index 49b314912..3abccff8f 100644 --- a/tests/functional/s/slots_checks.txt +++ b/tests/functional/s/slots_checks.txt @@ -1,13 +1,15 @@ -invalid-slots:36:0:36:9:Bad:Invalid __slots__ object:UNDEFINED -invalid-slots:39:0:39:15:SecondBad:Invalid __slots__ object:UNDEFINED -invalid-slots-object:43:22:43:23:ThirdBad:Invalid object '2' in __slots__, must contain only non empty strings:INFERENCE -invalid-slots:45:0:45:15:FourthBad:Invalid __slots__ object:UNDEFINED -invalid-slots-object:49:27:49:29:FifthBad:"Invalid object ""''"" in __slots__, must contain only non empty strings":INFERENCE -single-string-used-for-slots:51:0:51:14:SixthBad:Class __slots__ should be a non-string iterable:UNDEFINED -single-string-used-for-slots:54:0:54:16:SeventhBad:Class __slots__ should be a non-string iterable:UNDEFINED -single-string-used-for-slots:57:0:57:15:EighthBad:Class __slots__ should be a non-string iterable:UNDEFINED -invalid-slots-object:61:17:61:20:NinthBad:Invalid object 'str' in __slots__, must contain only non empty strings:INFERENCE -invalid-slots-object:64:17:64:26:TenthBad:Invalid object '1 + 2 + 3' in __slots__, must contain only non empty strings:INFERENCE -class-variable-slots-conflict:91:17:91:24:ValueInSlotConflict:Value 'first' in slots conflicts with class variable:UNDEFINED -class-variable-slots-conflict:91:45:91:53:ValueInSlotConflict:Value 'fourth' in slots conflicts with class variable:UNDEFINED -class-variable-slots-conflict:91:36:91:43:ValueInSlotConflict:Value 'third' in slots conflicts with class variable:UNDEFINED +invalid-slots:48:0:48:9:Bad:Invalid __slots__ object:UNDEFINED +invalid-slots:51:0:51:15:SecondBad:Invalid __slots__ object:UNDEFINED +invalid-slots-object:55:22:55:23:ThirdBad:Invalid object '2' in __slots__, must contain only non empty strings:INFERENCE +invalid-slots:57:0:57:15:FourthBad:Invalid __slots__ object:UNDEFINED +invalid-slots-object:61:27:61:29:FifthBad:"Invalid object ""''"" in __slots__, must contain only non empty strings":INFERENCE +single-string-used-for-slots:63:0:63:14:SixthBad:Class __slots__ should be a non-string iterable:UNDEFINED +single-string-used-for-slots:66:0:66:16:SeventhBad:Class __slots__ should be a non-string iterable:UNDEFINED +single-string-used-for-slots:69:0:69:15:EighthBad:Class __slots__ should be a non-string iterable:UNDEFINED +invalid-slots-object:73:17:73:20:NinthBad:Invalid object 'str' in __slots__, must contain only non empty strings:INFERENCE +invalid-slots-object:76:17:76:26:TenthBad:Invalid object '1 + 2 + 3' in __slots__, must contain only non empty strings:INFERENCE +invalid-slots:78:0:78:17:EleventhBad:Invalid __slots__ object:UNDEFINED +invalid-slots:81:0:81:16:TwelfthBad:Invalid __slots__ object:UNDEFINED +class-variable-slots-conflict:114:17:114:24:ValueInSlotConflict:Value 'first' in slots conflicts with class variable:UNDEFINED +class-variable-slots-conflict:114:45:114:53:ValueInSlotConflict:Value 'fourth' in slots conflicts with class variable:UNDEFINED +class-variable-slots-conflict:114:36:114:43:ValueInSlotConflict:Value 'third' in slots conflicts with class variable:UNDEFINED -- cgit v1.2.1