| """ |
| Checks that value used in a subscript supports subscription |
| (i.e. defines __getitem__ method). |
| """ |
| # pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position, unnecessary-comprehension |
| # pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order, useless-object-inheritance, redundant-u-string-prefix |
| import six |
| |
| # primitives |
| numbers = [1, 2, 3] |
| numbers[0] |
| "123"[0] |
| u"123"[0] |
| b"123"[0] |
| bytearray(b"123")[0] |
| dict(a=1, b=2)['a'] |
| (1, 2, 3)[0] |
| |
| # list/dict comprehensions are fine |
| [x for x in range(10)][0] |
| {x: 10 - x for x in range(10)}[0] |
| |
| |
| # instances |
| class NonSubscriptable(object): |
| pass |
| |
| class Subscriptable(object): |
| def __getitem__(self, key): |
| return key + key |
| |
| NonSubscriptable()[0] # [unsubscriptable-object] |
| NonSubscriptable[0] # [unsubscriptable-object] |
| Subscriptable()[0] |
| Subscriptable[0] # [unsubscriptable-object] |
| |
| # generators are not subscriptable |
| def powers_of_two(): |
| k = 0 |
| while k < 10: |
| yield 2 ** k |
| k += 1 |
| |
| powers_of_two()[0] # [unsubscriptable-object] |
| powers_of_two[0] # [unsubscriptable-object] |
| |
| |
| # check that primitive non subscriptable types are caught |
| True[0] # [unsubscriptable-object] |
| None[0] # [unsubscriptable-object] |
| 8.5[0] # [unsubscriptable-object] |
| 10[0] # [unsubscriptable-object] |
| |
| # sets are not subscriptable |
| {x ** 2 for x in range(10)}[0] # [unsubscriptable-object] |
| set(numbers)[0] # [unsubscriptable-object] |
| frozenset(numbers)[0] # [unsubscriptable-object] |
| |
| # skip instances with unknown base classes |
| from some_missing_module import LibSubscriptable |
| |
| class MaybeSubscriptable(LibSubscriptable): |
| pass |
| |
| MaybeSubscriptable()[0] |
| |
| # subscriptable classes (through metaclasses) |
| |
| class MetaSubscriptable(type): |
| def __getitem__(cls, key): |
| return key + key |
| |
| class SubscriptableClass(six.with_metaclass(MetaSubscriptable, object)): |
| pass |
| |
| SubscriptableClass[0] |
| SubscriptableClass()[0] # [unsubscriptable-object] |
| |
| # functions are not subscriptable |
| def test(*args, **kwargs): |
| return args, kwargs |
| |
| test()[0] |
| test[0] # [unsubscriptable-object] |
| |
| # deque |
| from collections import deque |
| deq = deque(maxlen=10) |
| deq.append(42) |
| deq[0] |
| |
| |
| class AbstractClass(object): |
| |
| def __init__(self): |
| self.ala = {i for i in range(10)} |
| self.bala = [i for i in range(10)] |
| self.portocala = None |
| |
| def test_unsubscriptable(self): |
| self.bala[0] |
| self.portocala[0] |
| |
| |
| class ClassMixin(object): |
| |
| def __init__(self): |
| self.ala = {i for i in range(10)} |
| self.bala = [i for i in range(10)] |
| self.portocala = None |
| |
| def test_unsubscriptable(self): |
| self.bala[0] |
| self.portocala[0] |
| |
| |
| def return_an_int(param): |
| """Returns an int""" |
| if param == 0: |
| return 1 |
| return 0 |
| |
| |
| def test_one(param): |
| """Should complain about var_one[0], but doesn't""" |
| var_one = return_an_int(param) |
| return var_one[0] # [unsubscriptable-object] |