-
Notifications
You must be signed in to change notification settings - Fork 48
Various improvements to provisional.py #387
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
base: main
Are you sure you want to change the base?
Conversation
aeliasso
commented
Sep 19, 2025
- abc.abstractproperty is deprecated. Fix by using property and abstractmethod instead.
- Fix the type of the stable property.
- Fix the property overriding syntax.
- Start the text in the provisional features' docstrings with a blank line to make it render as a paragraph block. Previously the backticks would not render as typewriter text.
- Fix type hints in parse_provisional.
- Reformat the file using Black.
|
||
@property | ||
def stable(self) -> bool: | ||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a significant knee-jerk dislike of this. Why do this instead of stable = True
, etc. -- what's the benefit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand it, it's how properties are supposed to be overridden. @abstractproperty
is a deprecated way of defining a read-only property which has been replaced with the syntax: @property @abstractmethod
. ( https://docs.python.org/3/library/abc.html#abc.abstractproperty )
Since it's a property, it needs to be overridden in subclasses. If assigned using = I think you are instead replacing the read-only property with an attribute which is read-write.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From that thread:
I guess there's no way for an ABC to indicate that a class variable is required.
Buh. I really want to keep my stable = True
syntax; if there is no go-to way to express mandatory class variables, we have to roll our own. I guess we could do that in feature
. Something like:
def feature(cls: type[ProvisionalFeature]):
assert issubclass(cls, ProvisionalFeature)
for (attr, type) in (('__doc__', str), ('short', str), ('stable', bool)):
assert hasattr(cls, attr) and isinstance(getattr(cls, attr), type), attr
singleton = cls()
features[singleton.tag()] = singleton
return singleton
@mandolaerik Your opinion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If assigned using = I think you are instead replacing the read-only property with an attribute which is read-write
No. Consider:
class X:
foo = 1
class Y:
@property
def foo(self): return 1
In X, foo
is available on class level, in Y the value is only available from the instance. You can say X.foo = 2
to change the class member, and you can shadow the class member in one specific instance by X().foo = 3
. In Y, you can also change the class member, Y.foo = 4
. Y().foo
is indeed a read-only expression, in the sense that Y().__setattr__
rejects foo
. However, the same is true for X if you seal the set of members through e.g. __slots__
.
So, if you insist that properties are kept read-only on instance level, then use __slots__
or equivalent (e.g. dataclass
). Or, if you want hard guarantees that thiings you intend as immutable stay immutable, then don't use Python.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I get it now. You are only using these classes at the class level, not as instances. I didn't realize. In that case my change is indeed incorrect. Also in that case, I think the second part of the comment quoted is applicable:
It sounds like you're really looking for a way to specify a structural subtype. A Protocol may serve your purposes better than an ABC.
I have to read up on Protocol before I have an opinion on that. Assuming you want to keep the code as is, however, then I would like to turn the question around: Why do you declare these class members as properties in the abstract base class? To cause an error if a subclass forgets to override them, e.g. because the property is not printable?
Erik, in you example:
>>> class Y:
... @property
... def foo(self): return 1
...
>>> type(Y.foo)
<class 'property'>
>>> Y.foo=2
>>> type(Y.foo)
<class 'int'>
Y.foo is now an int and the original property is no more. It has ceased to exist. It is a late property. If this is the expected use of the abstract base class, then why declare a property in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point with Y.foo=2 is that python is hopelessly dynamic: even though the property is read-only in one sense, it's still possible to lift that protection. Nothing is truly protected. In particular, you might say:
class X:
@property
@abstractmethod
def foo(self): pass
with the intention that overrides should be read-only as in:
class Y(X):
@property
def foo(self): return 1
but Python will happily swallow if someone says
class Z(X):
foo = 2
Thus, a user of X
does not have an immutability guarantee on foo
.
* abc.abstractproperty is deprecated. Fix by using property and abstractmethod instead. * Fix the type of the stable property. * Fix the property overriding syntax. * Start the text in the provisional features' docstrings with a blank line to make it render as a paragraph block. Previously the backticks would not render as typewriter text. * Fix type hints in parse_provisional. * Reformat the file using Black.
Line length is 79 characters as per the Simics Python Style Guide.
653d4aa
to
d7233ab
Compare
@@ -0,0 +1,2 @@ | |||
[tool.black] | |||
line-length = 79 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not inherently opposed to this, but neither me nor Erik are using Black. You are free to use it, of course -- but enshrining it into the repo feels a bit much. The only one style guide DMLC is beholden to is Intel's own. I'd be OK with you putting pyproject.toml
in the .gitignore
though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know about Black before. I'm open to try enforcing it for the DMLC repo, but it doesn't belong to this PR.
More specifically: Feel free to blackify all python files in the DMLC repo. The repo is small enough that we probably can sweep through the diff manually and see if it's a net win. If it is, then let's pioneer it by enforcing it with a test.