Check property decorators stricter#19313
Conversation
| return False | ||
| if not isinstance(deco.expr, NameExpr) or deco.expr.name != property_name: | ||
| return False | ||
| if deco.name not in {"setter", "deleter"}: |
There was a problem hiding this comment.
| if deco.name not in {"setter", "deleter"}: | |
| if deco.name not in {"getter", "setter", "deleter"}: |
@x.getter is valid at runtime (albeit not common). We probably don't want to emit an "Only supported top decorators are ..." error for it.
I guess we don't have any tests for it 🤷
There was a problem hiding this comment.
Hm. This definitely needs a test, but I think rejecting @prop.getter is a reasonable thing to do: it should override the existing getter, supporting it properly won't be trivial, so explicitly saying "we don't support redefined getters" is not that bad (given that such usage should be really rare, 0 primer hits)
There was a problem hiding this comment.
By following this github search, I identified two common patterns with @prop.getter (excluding partial subclass overrides as they don't trigger this code and aren't supported anyway):
-
Mistake with
getterinstead ofsetter(followed by signaturedef (self, value)) -
Obscure way of defining properties:
class A: @property def foo(self): pass @foo.getter def foo(self): ... # Some logic here @foo.setter def foo(self, new_foo): ...
Honestly this makes my eyes bleed. I don't know how popular this is as regex code search is limited to 5 pages, and the file count estimate is never close to reality, they don't actually regex-match whole github. I propose to accept the risk and wait - if we get a couple of tickets about this in the next release, we can whitelist
getteras well.
As a secondary reference, pyright handles this in the most confusing manner possible, we don't want to replicate that behaviour. It silently accepts any @prop.getter even with incompatible return type and ignores it completely - see my ticket microsoft/pyright#10633
There was a problem hiding this comment.
The relevant pyright ticket was closed wontfix, but I still think allowing getter and ignoring it isn't optimal:/
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
brianschubert
left a comment
There was a problem hiding this comment.
LGTM!
Left some non-essential comments
| if self._is_valid_property_decorator(first_node, func_name): | ||
| # Get abstractness from the original definition. | ||
| item.func.abstract_status = first_item.func.abstract_status | ||
| if first_node.name == "setter": |
There was a problem hiding this comment.
Would it make sense to warn about duplicate setters/deleters here?
There was a problem hiding this comment.
Property support is fragile, I'm afraid to touch it too deeply:) This is definitely a good idea, but I'll defer that to a follow-up PR - let's keep such changes as minimal as possible.
This comment has been minimized.
This comment has been minimized.
|
According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅ |
Fixes #19312. Fixes #18327.
Only accept
@current_prop_name.{setter,deleter}as property-related decorators.