Solvedpylint [Python 3.9] Value 'Optional' is unsubscriptable (unsubscriptable-object) (also Union)

hjwp
441

Steps to reproduce

Install Python 3.9, then:

# minimal_repro.py
from typing import Optional, Union
foo: Optional[int] = 3
bar: Union[int, str] = 4

Current behavior

Pylint reports

minimal_repro.py:3:5: E1136: Value 'Optional' is unsubscriptable (unsubscriptable-object)
minimal_repro.py:4:5: E1136: Value 'Union' is unsubscriptable (unsubscriptable-object)

Expected behavior

This isn't an error in Python 3.8 so I don't think it should be an error in 3.9?

pylint --version output

pylint 2.6.0
astroid 2.4.2

(I tried pip install pylint astroid --pre -U)

13 Answers

✔️Accepted Answer

Also encountering this with the Union type in Python 3.9: https://github.com/dkmiller/pyconfigurableml/pull/16/checks?check_run_id=1217453549

Other Answers:

@metal3d Pylint 2.7.1 is the latest version and I believe the problem you see should have been fixed in version 2.7.0, so try to update Pylint.

Self-contained reproducer, which is not Python 3.9 dependent (but the typing issue is 3.9 dependent):

class deco:
    def __init__(self, f):
        self.f = f

    def __getitem__(self, item):
        return item


@deco
def Optional():
    pass


print(Optional[int])

Probably related to #2578:

pylint doesn't currently correctly understand decorators

Looks like some code give up checks if the function is decorated, IIRC:

if isinstance(owner, astroid.FunctionDef) and owner.decorators:
    return False

it would be a simple quick-fix if we have no good way of studying the decorator from now.

As my reproducer is not 3.9 specific I'm digging about why the initial reproducer is failing on 3.9:

  • The inferred function on line 1722 of typecheck.py is Optional in 3.9
  • The inferred function on line 1722 of typecheck.py is Union in 3.8

Optional in 3.8 is declared as:

Optional = _SpecialForm('Optional', doc=...)

while in 3.9 it's declared as:

@_SpecialForm
def Optional(self, parameters):
    ...

As pylint does not resolve decorator, the inference is still OK in 3.8 (no decorator) but fails in 3.9 (decorated).

Looks like it could be fixed by using something like:

if inferred.decorators:
    first_decorator = helpers.safe_infer(inferred.decorators.nodes[0])
    if isinstance(first_decorator, astroid.ClassDef):
        inferred = first_decorator.instantiate_class()
    else:
        return  # TODO: Handle decorators that are not classes

in visit_subscript in typecheck.py.

More Issues: