"None" in Python code breaks code suggestions in vscode

Question:

[ This was a bug in vscode < v1.71, see my comment with additional screenshots. ]

I’ve got a weird issue in vscode. For some reason, code completion of c. stops working after the first None in the Python code, as shown in below screenshot.

After first None, it is like c. contains nothing

This is the complete Card class (complete source code, see link below):

from dataclasses import asdict
from dataclasses import dataclass
from dataclasses import field

@dataclass
class Card:
    summary: str = None
    owner: str = None
    state: str = "todo"
    id: int = field(default=None, compare=False)

    @classmethod
    def from_dict(cls, d):
        return Card(**d)
    def to_dict(self):
        return asdict(self)

It is like if c. contains nothing after that. I just get "No suggestions." when using Ctrl+. at c..

If i put None in quotes, like "None", suggestions works for following rows. Until the next None that is.

If I change to False, suggestions works for following rows. It just seems to happen for None!

It is also contained within the function scope too.

Any idea why this is happening?

The code is used in the Pytest book and can be download from Python Testing with pytest, Second Edition.

The file my problem is from is: code/ch2/test_card.py

Reinstalled vscode
The problem remains after a complete reinstallation of vscode, including manually deleting the "~/.config/Code/" and "~/.vscode/" folders.

Environment:

  • Ubuntu 20.04
  • Python 3.10.4 virtual environment using pyenv
  • vscode extensions:
    • HTML CSS Support
    • Python
      • That autoinstalled Pylance, Jubyter, Jupyter Keymap and Jupyter Notebook Renderers
    • Python Environment Manager
    • rust-analyzer
Asked By: tsvenson

||

Answers:

Seems to be related to type annotations.

If you remove variable type annotation in Card class in cards_projsrccardsapi.py file. Then the intellisense will work fine.

Source code:

class Card:
    summary: str = None
    owner: str = None
    state: str = "todo"
    id: int = field(default=None, compare=False)

change into:

class Card:
    summary = None
    owner = None
    state = "todo"
    id = field(default=None, compare=False)

enter image description here

If you only remove type annotations for some variables, like below.

class Card:
    summary: str = None
    owner: str = None
    state = "todo"
    id = field(default=None, compare=False)

Then when the variable with the type annotation is assigned none, the following intellisense will be invalid.

enter image description here

summary is None, the following code cannot get suggestions

enter image description here

summary is not None, the following code can get suggestions

enter image description here

summary is not None, but owner is None, the following code cannot get suggestions

Answered By: JialeDu

If you are going to use type hints, I suggest you configure vscode to do Mypy type checking to avoid these kind of errors.

If you annotate the type as str and then assign it a value of None, and you have Mypy type checking, this will trigger an incompatible type warning.

screenshot vscode incompatible type

Because you have annotated the type as str. Vscode will think that the 2nd assertion is unreachable:

c = Card()
assert c.summary is None # assertion always fails because c.summary is string
assert c.owner is None # this statement is unreachable

The 2nd assertion
Screenshot shows that vscode thinks 2nd assertion is never reached because the 1st assertion will always fail because a string type will never be none.
Screenshot never reached

To correct use the Optional type hint when assigning None.

from dataclasses import asdict
from dataclasses import dataclass
from dataclasses import field

from typing import Optional, Any, Dict

@dataclass
class Card:
    summary: Optional[str] = None
    owner: Optional[str] = None
    state: str = "todo"
    id: Optional[int] = field(default=None, compare=False)

    @classmethod
    def from_dict(cls, d: Dict[str, Any]) -> "Card":
        return Card(**d)
    def to_dict(self) -> Dict[str, Any]:
        return asdict(self)

As a final point, I think you have absolutely done the right thing. In my view, autocomplete is critically important in avoiding mistakes. If autocomplete isn’t working you should stop, figure out why, and do not continue until you get autocomplete working again.

Answered By: mpette

This seems to be a quirk of VS Code on Ubuntu combined with sloppy type hinting.

I really should have used the types as mpette noted, using Optional[X] = None:

@dataclass
class Card:
    summary: Optional[str] = None
    owner: Optional[str] = None
    state: str = "todo"
    id: Optional[int] = field(default=None, compare=False)

Or even the newer bar form X|None:

@dataclass
class Card:
    summary: str|None = None
    owner: str|None = None
    state: str = "todo"
    id: int|None = field(default=None, compare=False)

However, even on a mac, the second form seems to confuse VSCode.

Also, VSCode on my mac seems to deal with the original form just fine. Odd that it’s different behavior on Ubuntu.

Answered By: Okken

This was a bug in vscode < v1.71

I was just about to get started thoroughly testing the suggestions @mpette, @JialeDu and @Okken provided in their comments.

However, I was met with that v1.71 had been installed, and now it works with the original code, as shown in the screenshot.

Suggestions after None works gain

So it seems to me this was indeed a bug in the previous version of vscode, as the Python extensions still needs to be reloaded for their updates to take affect:

Python extensions not updated

After reloading them, suggestions keeps working as they should 🙂

Thanks everyone who so kindly tried to help me get this fixed.

Answered By: tsvenson