-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Abstract class properties report inconsistent typing #2601
Comments
The abstract base class indicates that subclasses need to implement a classmethod property, but in this sample they're overwriting the I can think of two options here:
class M1(BaseModel):
@classmethod
@property
def model_code(cls) -> str:
return "m1"
class BaseModel(Protocol):
model_code: ClassVar[str]
class M1:
model_code = "m1"
class M2:
model_code = "m2" |
Except then why does
Yes, I know that will work, but it just doesn't look as clean as the original solution I had...
That doesn't accomplish my first goal. Consider: from typing import Protocol
class BaseModel(Protocol):
model_code: str
class M1(BaseModel):
pass
# model_code = "m1"
class M2(BaseModel):
model_code = "m2"
m1 = M1() pylance (with basic type checking on) doesn't report any error, while mypy does say Ideally, the type checker would pick up that the subclass didn't define everything it should as represented by the parent class that is a |
@erictraut sorry I thought I had posted this comment and then you closed the issue... |
In the protocol case, you wouldn't subclass from the protocol. In other words, from typing import Protocol
class BaseModel(Protocol):
model_code: str
class M1:
pass
class M2:
model_code = "m2"
m1: BaseModel = M1() # Error! |
So the confusion arises because the error message says:
but In other words, the error message is saying the declared type is "property", but
Thanks. Now I get it. The example I saw somewhere on the web misled me in terms of how |
I'm having a little trouble wrapping my head around this. Is there a way to do this that both gives runtime protections and makes pylance happy? I've got this: class WithProp:
@property
def name(self) -> str:
raise NotImplementedError()
class NoProp(WithProp):
name = "cool" which works great at runtime - if someone doesn't overwrite Thanks much! |
Since the base class implements a read-only property (a getter with no setter), the child class should do the same. class NoProp(WithProp):
@property
def name(self):
return "cool" |
Got it! I appreciate the response. I think it makes sense as the "most correct" approach typing wise, but this feels like a pretty common Python pattern. It would be great to be able to write the above code without typing complaints. |
Workaround: If the base class is defined as:
then derived classes can use either properties or simple members without triggering additional type errors. |
`pyright` keeps complaining about `money` not being a property. `mypy` does not. The rationale of `pyright` developers seem to be right: microsoft/pyright#2601 (comment)
Note regarding that workaround: the type declaration must come after the property definition as shown in the example. Thanks for the workaround, @dgrunwald! |
Describe the bug
This is related to microsoft/pylance-release#435 but with the latest version of pyright, types seem inconsistent and I'm getting new messages that weren't there before.
To Reproduce
This reports:
Note that the error message says you can't assign them (the base class has type property, but it should be "abstract class property that is a
str
", butreveal_type
says they are bothstr
, which intuitively is saying you should allow that assignment.Expected behavior
I would like it where the assignment was allowed. Idea here is that the
model_code
becomes a lookup telling you which class to instantiate.VS Code extension or command-line
VS Code 1.62.3
pylance 2021.11.2
Additional context
I know there has been debate in multiple issues (e.g., microsoft/pylance-release#157 and microsoft/pylance-release#435) about how to handle abstract class properties, with arguments that say you are overriding the type of
model_code
in the subclass, where the parent class sees it as a property, and the subclass sees it asstr
, but I don't see how to make this work with typing where I accomplish the following goals:Note that if I change
BaseModel
to just havemodel_code: str
rather than the abstract class property, the code still works, but then I don't accomplish the first goal listed above.Maybe the
reveal_type(BaseModel.model_code)
is what is being reported incorrectly, which is a bug to fix, so then you could see the mismatch in types. mypy reports it asRevealed type is "def () -> builtins.str"
But I would still like to figure out how to accomplish my goals....
The text was updated successfully, but these errors were encountered: