davidhalter / jedi

Awesome autocompletion, static analysis and refactoring library for python
http://jedi.readthedocs.io
Other
5.78k stars 507 forks source link

Typing when generics are involved do not work #1095

Closed brettcannon closed 5 years ago

brettcannon commented 6 years ago

From Microsoft/vscode-python#1347:

from typing import Generic, TypeVar, List

T = TypeVar('T')

class A(Generic[T]):
    def __init__(self, x: T):
        self._x = x

    def get_value(self) -> T:
        return self._x

a1 = A('')
a1.get_value().  # Works as expected.

a2 = A[str]('')
a2. # No completions.
kshpytsya commented 5 years ago

My use-case involves descriptor protocol.

import jedi

def strip_under(l):
    return [i for i in l if not i.startswith("_")]

def split3(s1, s2):
    s1 = set(s1)
    s2 = set(s2)
    print("A - B : ", sorted(s1 - s2))
    # print("A & B : ", sorted(s1 & s2))
    print("B - A : ", sorted(s2 - s1))

src = """
import typing
from somewhere import something

class Record:
    pass

T = TypeVar("T")

class Field(Generic[T]):
    def __set_name__(self, owner: typing.Type[Record], name: str) -> None:
        pass

    def __set__(self, instance: Record, value: str) -> None:
        pass

    def __delete__(self, instance: Record) -> None:
        pass

    def __get__(self, instance: Record, owner: typing.Type[Record]) -> T:
        # return ""
        return typing.cast(T, something())

class R(Record):
    f1 = Field[str]()

r = R()
r.f1.
"""

lines = src.split("\n")[:-1]
script = jedi.Script(
    source=src,
    line=len(lines),
    column=len(lines[-1]),
    path="source.py",
)

completions = script.completions()
split3(strip_under(dir(str)), strip_under([i.name for i in completions]))

running the latest master (946869ab) results in

A - B :  ['capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
B - A :  []

whereas changing

     def __get__(self, instance: Record, owner: typing.Type[Record]) -> T:
-        # return ""
+        return ""
         return typing.cast(T, something())

produces

A - B :  []
B - A :  []

Does supporting this require a lot of effort?

davidhalter commented 5 years ago

@kshpytsya Please note that both TypeVar and Generic are undefined names. Use typing. ahead of those names and it works.

For me it even works when I remove the typing.cast stuff (which I have just implemented, latest master).

kshpytsya commented 5 years ago

@davidhalter my bad. The code above was obviously an attempt at reproduction in a minimal example. The real culprit in my actual tests (yes, I have unittests testing jedi completions for my library) was having the following in tox.ini:

[testenv]
deps =
         pytest
         coverage
         jedi
         git+https://github.com/davidhalter/jedi
         # git+https://github.com/kshpytsya/jedi@typeshed

Which "appeared" during me trying to deal with #1319. Guess which version of jedi I had in test environment.

davidhalter commented 5 years ago

Fixed with 0.14.0.