pylint
pylint copied to clipboard
False positive with E1136 unsubscriptable-object
Steps to reproduce
- Create file
z.py
a = None
while True:
if a is None or a["1"] == 0:
a = {"1": 1}
else:
break
print("Done")
- run
pylint z.py
Current behavior
E: 3,20: Value 'a' is unsubscriptable (unsubscriptable-object)
Expected behavior
no errors, no warnings
pylint --version output
pylint 1.7.1,
astroid 1.5.2
Python 2.7.13 (default, Dec 18 2016, 07:03:39)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)]
This has hit us too. We are using a variable that is initialized to None, but then gets assigned to dict in a loop.
I think something like this will trigger it too:
points = [{"lat": 39, "lon": -92}, {"lat": 39.1, "lon": -92.1}]
furthest_west = None
for p in points:
if furthest_west is None:
furthest_west = p
else:
if p['lon'] < furthest_west['lon']:
furthest_west = p
not sure how you would solve this, seems like the inferencer would have to go into the if/else clauses to see what might get assigned to the variable to figure out that it's Union(None, dict).
Even checking isinstance(thing, list) immediately prior to using thing will trigger this.
Yes @hughes that's a problem that's still crippling pylint even today (but hopefully with the new number of committers we have, we might tackle it at some point). I'm referring here to the fact that pylint does not quite grasp control flow, that is, if you use isinstance, pylint will happily infer all potential values that a variable could have, disregarding the branch hints.
I had this problem today opening a config file.
+1
I have this false positive too. I reference a variable instanced as none in the main object class, and then change it in function from an inherited class. Code example below; incomplete for brevity.
class Response():
def __init__(self):
self.raw_response = None
def filter_raw_response(self):
if not self.raw_response:
return None
num_datapoints = len(self.raw_response['Datapoints']) # Error shows here
if num_datapoints == 0:
return None
class SpecificResponse(Response):
def craft_response(self)
# Variable instanced here:
self.raw_response = self.client.get_metric_statistics()
+1
I got this too when I tried to iterate over candidates, a matrix like variable. It reports item as NoneType and raise E1136 error. But, actually, it is a list.
candidates = [item for item in val_dataset if item[-1] == i]
candidates = random.sample(candidates,100)
for item in candidates:
img_path = os.path.join(data_dir,item[0])
out_path = os.path.join(output_folder,str(i))
os.system('cp %s %s'%(img_path,out_path))
False positive even if the custom class implements the __getitem__ method.
Will this ever be fixed then?
@melikyuksel Unless someone proposes a patch, it's unlikely.
+1
I got this too when I tried to iterate over candidates, a matrix like variable. It reports item as NoneType and raise E1136 error. But, actually, it is a list.
candidates = [item for item in val_dataset if item[-1] == i] candidates = random.sample(candidates,100) for item in candidates: img_path = os.path.join(data_dir,item[0]) out_path = os.path.join(output_folder,str(i)) os.system('cp %s %s'%(img_path,out_path))
I had the same issue when using random.sample
Would this actually be a false positive? Seems to me it is following the intended behavior.
Used when there is a reference to an object that initialized as a non-subscriptable object
http://pylint-messages.wikidot.com/messages:e1136
@sgornic The solution there is suggestion to used [] to initialize an empty list instead of using None to remove the error but doing that cause an unwanted/undesirable behavior in python. See here https://nikos7am.com/posts/mutable-default-arguments/ +1 I am experiencing the same issue while initializing a variable with None and rewriting this with some other values given that program runs without an error
There is also issue #2063 that seems to describe the same error.
I also get this with the built-in Exception.args and believe it is the same error:
class HTTPError(Exception):
def __init__(self, status, reason):
super(HTTPError, self).__init__(status, reason)
@property
def status(self):
return self.args[0] # pylint reports: E1136: Value 'self.args' is unsubscriptable
@property
def reason(self):
return self.args[1] # same
Just make your list Python3 compatible: i.e.: my_list = [1, 2, 3, 4] for _my in list(my_list): pass
I'm also seeing this with __getitem__ implemented
I'm getting the same with a Pandas DataFrame:
endog = dta["colName"] # [E1136 unsubscriptable-object] Value 'dta' is unsubscriptable
...
dta[["c1", "c2"]] # [E1136 unsubscriptable-object] Value 'dta' is unsubscriptable
Output of python --version: Python 3.6.10 :: Anaconda, Inc.
a similar thing also occurs with bidict
a similar thing also occurs with bidict
Bidict author here. Just noticed this spurious error from pylint when using Python 3.9 and found my way to this issue.
(.venv39) jab@tsmbp ~/s/bidict (dev)> pre-commit run -a
...
pylint...................................................................Failed
- hook id: pylint
- exit code: 2
************* Module bidict._typing
bidict/_typing.py:17:17: E1136: Value '_t.Union' is unsubscriptable (unsubscriptable-object)
bidict/_typing.py:20:6: E1136: Value '_t.Union' is unsubscriptable (unsubscriptable-object)
bidict/_typing.py:32:6: E1136: Value '_t.Union' is unsubscriptable (unsubscriptable-object)
bidict/_typing.py:33:6: E1136: Value '_t.Union' is unsubscriptable (unsubscriptable-object)
In all these cases, _t.Union refers to typing.Union, which is in fact subscriptable. See for example this code (picking the first line flagged above, bidict/_typing.py:17, as an example).
This result is given by pylint 2.6.0 (as can be seen here), the latest stable release.
The spurious error does not occur when using the same version of pylint under Python 3.6, 3.7, or 3.8.
Hope this helps.
@technillogue / @jab thanks for your report/investigation.
The problem you mention is a bit different from the original one (i.e not due to a lack of control flow) but linked to python 3.9.
It seems to be the same issue as #3882.
Happens when using hinting:
def my_func(rgb: tuple[int, int, int]):
....
same error: E1136: Value 'tuple' is unsubscriptable (unsubscriptable-object)
same error:
E1136: Value 'tuple' is unsubscriptable (unsubscriptable-object)
tuple is unsubscribable (at least in 3.7, maybe not 3.9):
>>> from typing import Tuple
>>> Tuple[int, int, int]
typing.Tuple[int, int, int]
>>> tuple[int, int, int]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'type' object is not subscriptable
@kbakk good point.
I was just copy&pasting code from here: https://docs.python.org/3/library/typing.html
@kbakk @ricardoquesada thanks for your report.
In fact, starting with python3.9, tuple is indeed subscriptable.
With master branch of pylint and astroid, when linting the following code:
def my_func(rgb: tuple[int]) -> None:
rgb = None
return
with python3.7:
pylint --disable=all --enable=unsubscriptable-object bug_pylint_1498.py
************* Module bug_pylint_1498
bug_pylint_1498.py:1:17: E1136: Value 'tuple' is unsubscriptable (unsubscriptable-object)
---------------------------------------------------------------------
Your code has been rated at -6.67/10 (previous run: 10.00/10, -16.67)
and with python3.9:
pylint --disable=all --enable=unsubscriptable-object bug_pylint_1498.py
---------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: -6.67/10, +16.67)
I'm not closing this issue, because original issue is not the same as the one we are dealing with here.
This issue also appears where the variable in question is a class attribute, as in the following minimal example:
class MyClass:
my_cashed_value = None
def get_message(self):
result = MyClass.my_cashed_value
if result is not None:
return result["message"]
else:
message = "my cached message"
MyClass.my_cashed_value = {"message": message}
return message
(using pylint 2.6.0 and python 3.8.3)
@BenLatham thank for your report.
In your case, pylint is understanding that my_cashed_value maybe None because of its initialization.
If you change my_cashed_value = None for my_cashed_value = dict() then the issue disappears.
Similar issue here using python3.8. In this example
"""
whatever
"""
from typing import Optional, Dict
def func(i) -> Optional[Dict]:
"""
func
"""
return {i: i} if i else None
x = func(1)
print(x[1])
x = func(0)
print(x[0])
I get
09:20 $ pylint test.py
************* Module test
test.py:18:6: E1136: Value 'x' is unsubscriptable (unsubscriptable-object)
-------------------------------------------------------------------
Your code has been rated at 2.86/10 (previous run: -1.43/10, +4.29)
on the second call to func. pylint is quite smart, but in more complex examples it seems to give up and simply report a variable that might be None to be unsubscriptable. Is that the case?
Yes, @andrea-cassioli-maersk astroid do not have real control flow (no restriction on the inference after isinstance(x, dict) for example) but can handle simple cases like the one you gave.
I'm still not understanding why pylint can infer this case correctly:
def func(i) -> Optional[Tuple]:
return (i, i) if i else None
print(func(1)[0]) # OK
print(func(0)[0]) # unsubscriptable-object
but not this:
foo: Optional[Tuple] = None
print(foo and foo[0]) # unsubscriptable-object (??)