Describe the bug
I'm using type comments for compatibility with Python 2 in a large project. While trying pyright to replace pyls (used with Emacs lsp-mode), I encountered an error with every method that has a type comment for the self or cls parameter: "Parameter annotation count mismatch: expected {N} but received {N+1}".
To Reproduce
foo.py from this gistpyright foo.pyExpected behavior
For this example file, pyls and mypy don't detect any error, and neither should pyright.
Screenshots or Code
Sample code in this gist

VS Code extension or command-line
Forgot to add: if I change the type comments to type annotations (def get_one(cls: Type[BM], **kwargs: Any) -> Optional[BM]...), pyright doesn't report any error. So this issue is really only with type comments.
Sadly migrating to proper type annotations is not really practical for me:
I only recently added type comment support for functions/methods. My hesitance in adding this support was that it uses a syntax and set of rules that were never ratified as part of the official Python spec. To the best of my knowledge, type comments evolved somewhat organically and were never fully documented or spec'ed in any form. My implementation in Pyright is based on reverse-engineering existing samples I could find. Those samples all omitted the type for the "self" and "cls" parameters on methods. It looks like your type comments include annotations for these parameters, so I'm confused how that worked.
Perhaps you know of some formal documentation or specs that I have missed that could provide clear and definitive rules around type comments? Or can you shed any light on the "self" and "cls" parameter issue I mentioned above?
I'm not aware of any formal spec either. As far as I can tell, PEP 0484 only states that "for methods, no type is needed for self". No example anywhere specify a type for cls or self when using the "short form" # type: (arg_type) -> return_type.
But at the same time, nothing in the spec forbids to add a type when using the "long form", so the following should be valid IMO:
def get_one(cls, # type: Type[BM]
**kwargs
):
# type: (...) -> BM
...
So I had a quick look at other implementations:
With the Python 3 type annotation syntax, there's never ambiguity about which type annotations go with which parameters. With this old-style syntax for specifying all of the input parameter types on the line after the signature, the rules appear to be more complex.
I guess that the type checker can accommodate both _n_ and _n - 1_ annotations (where _n_ is the number of parameters in the signature) when there is a "self" or "cls" parameter present. It sounds like that's what the other type checkers are doing.
I've updated the logic to support both _n_ and _n-1_ annotations for class and instance methods. This support will be in the next version of Pyright.
Thanks a lot @erictraut!
This is now addressed in Pyright 1.1.66, which I just published. The change will also be in the next release of Pylance.
Most helpful comment
I've updated the logic to support both _n_ and _n-1_ annotations for class and instance methods. This support will be in the next version of Pyright.