Search code examples
pythonvisual-studio-codepylance

Why doesn't parameter hint highlighting work in VS Code while unpacking Python class objects?


I've encountered a problem with argument highlighting while unpacking a class into a function: Python can't figure out amount of arguments I want to provide while unpacking a class

Let's say we have a function:

def somefunc(attr1, attr2, a,b,c,d,e,f): 
    pass

I want to unpack an object and expect vs code to know the object unpacks to 2 arguments. It works just fine with tuples (VS Code knows the size of tuple and highlights the next argument):

data1 = ("Hello", "World")
somefunc(*data1,1,2,3,4,5,6)

argument highlighting when unpacking a tuple

but I want to unpack classes as well:

class foo:
      attr1: str
      attr2: str
      def __init__(self, attr1, attr2):
            self.attr1 = attr1
            self.attr2 = attr2
      def empty():
            return foo(None,None)
      
      def __iter__(self):
            return iter((self.attr1, self.attr2))

When I try to write some code with this implementation:

data2 = foo("Hello", "World")
somefunc(*data2,1,2,3,4,5,6)

it doesn't work:

argument highlighting when unpacking a class object

What can I do to fix this? Is it a code highlighter problem, or it can be fixed with some type annotations and tricks?

I am using "pylance, python, python debugger" extensions from Microsoft for my Python code


Solution

  • In general, with static analysis stuff like this, you need to put yourself in the shoes of the static analysis tooling and the implementors of that tooling. julaine's comment hits the nail on the head of how to think:

    I guess the trouble is knowing how many elements __iter__ is going to return, and while it is obvious in your case, it is generally impossible to tell, even with type annotations. Since the most common reason to implement __iter__ is to program a collection-like-class, it might be that no part of vscode considered your special case important enough to implement. But I am just speculating on that last part.

    That being said, it does seem that Pylance takes length information into account from this section of the release notes, but from testing with an implmentation of __len__ that returns 2, I don't think Pylance supports that either.

    I think that wording in the release notes is about well-known iterable types like lists and tuples.

    You can get what you want from Pylance if you switch to this:

    from typing import Tuple
    class foo(Tuple[str,str]):
    

    , which I think is thanks to a change made in Pylance 1.1.63, but extending Tuple is not a trivial type change.

    Hopefully I'm not missing something, but I'm not a regular Python dev, so I likely am.

    If you want something different, you may want/need to raise a feature-request issue ticket.


    Fun fact: you can see analogous discussion/info in this answer to Declaring length of tuples in Python typing, which is about mypy (which is not relevant here, since Pylance uses Pyright).