I'm trying to make a subclass with a @classmethod that would take as arguments an instance of its superclass and kwargs for its other fields. The goal is to be able to take an object of the general class and "extend" it into an object of the subclass.
Doing this, I've noticed a behavior of VSCode which I don't understand: When writing a @classmethod, the cls argument does not provide the argument hinting that calling the class constructor directly does.
Consider the following example:
import dataclasses
from typing import Self
@dataclasses.dataclass(kw_only=True)
class A:
x: int
@dataclasses.dataclass(kw_only=True)
class B(A):
y: int
@classmethod
def from_a_1(cls, a: A, y: int) -> Self:
return cls(x=a.x, y=y) # cls() does not show argument hints
@classmethod
def from_a_2(cls, a: A, y: int) -> 'B':
return B(x=a.x, y=y) # B() does show hints just fine
a = A(x=1)
b_1 = B.from_a_1(a=a, y=2)
b_2 = B.from_a_2(a=a, y=2)
As the image on the left shows, for a direct class call B() it is possible to Trigger Parameter Hints, and also keyword arguments are shown in Trigger Suggest. The image on the right shows that the other variant, calling cls() makes Trigger Parameter Hints totally unavailable, and it does not show keyword arguments in Trigger Suggest.


This prompted me to think that perhaps I don't have a good understanding of using classmethods, or that something about this confuses VSCode. What is the difference between those two different ways of doing (in this case) the same thing?
Furthermore, are b_1 and b_2 really the same thing / do those 2 approaches lead to same results?
Also to address the possible XY problem, what is the proper/reasonable/pythonic way to (take object of superclass) -> (make it into an object of subclass and fill the extra fields)?
cls? There's no type hint, and statically there's no connection between the definition offrom_a_1and how you assume it will be called at runtime. (Further, the fact thatfrom_a_1will be bound to an instance ofclassmethodrather than the function defined by thedefstatement isn't something you can know statically; it requires an assumption about whatclassmethodis bound to and will do at runtime.)class C(B): pass, then you can callC.from_a_1(a, y)andclswill beC, notB