-
Notifications
You must be signed in to change notification settings - Fork 949
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
Use enums for constants #1743
Use enums for constants #1743
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
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.
You need to resolve the linter errors. Changing to upper-case seems most correct, but there were no lint problems before, so maybe it is due to how you changed the classes.
|
||
|
||
class Endian: # pylint: disable=too-few-public-methods |
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.
This should be replaced by the system constant.
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.
Not sure I understood, do you mean sys.byteorder
?
The change you wanted to make, is quite a different test, the test is checking the string representation of handle, not an individual component. There are no compatibility issue for a couple of reasons:
|
This comment was marked as resolved.
This comment was marked as resolved.
It is the default in many payload calls, and therefore it will not change anything if using the "official" constant instead. If you rename things that are real part of the API (meaning people will have to change their app) then add a line in API_CHANGES.rst. Yes I am happy with renaming, we have had changes like this in every 3.x version but never in 3.x.y versions. |
I'm getting there :)
This comment was marked as resolved.
This comment was marked as resolved.
restarted job. You can easily restart yourself:
|
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.
The only bigger item is the remove of init.
Please add a short description in API_CHANGES.rst (section 3.5) that constant now uses enums and are capital letters.
|
||
def __init__(self): |
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.
Why should we permit objects ? I do not see the need in contrary.
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.
Enum members are singletons by default, we don't need any special logic to guard them, Python handles that for us.
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.
It does not prohibit that I can assign the class to a variable and make changes, with unexpected results.
And as far as I know, if you instanciate the class you get a new set of class variables (elements of enum).
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.
And as far as I know, if you instanciate the class you get a new set of class variables (elements of enum).
Actually, I believe no, class variables are static. You can change them, but restricting __init__
won't prevent that anyway.
I think I should clarify, __init__
is used to initialise enum members, not the enum itself.
Enums are using metaclasses underneath. Say, if somebody does ModbusStatus(0xFFFF)
, they will get ModbusStatus.WAITING
, because enum members are singletons.
|
||
def __init__(self): |
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.
We should not permit to instantiate any constant class.
A question, why do you inherit from int, str ? I do not see anything in the class that makes use of it...you do not make a special int. |
It's the way to create derived enums. By default enum members are just unique constants with some value. However, in our case the values have meaning (like modbus code), so we want to control what the values are, and we want to use the enum members as the values. Thus, for hex constants I used assert ModbusStatus.WAITING == 0xFFFF Without the inheritance, we'd have to do assert ModbusStatus.WAITING.value == 0xFFFF which is more error-prone and less convenient to use. |
Good point ! Apart from when you look at comm_types in transport, that class inherits "class comm_types(Enum)" and the values are addressed directly as comm_types.TCP. Edit: |
A short example why you need to disable init:
Having different values for the same constant are likely to cause problems (and have done so). |
IDE is no good to us, we depend on CI to be the final judge. I simply do not like to remove this kind of protection unless it is absolutely nessecary , it will not provide 100% protection, just like constants can be assigned to, but it's better than nothing. I made the example to show that your argument about singleton doesn't not hold in this case. |
We are getting close to release time, so if you want this in please solve the outstanding issue, and request a new review. |
I added the changelog. @janiversen, sadly, I think it's impossible to disable If you have any other ideas how to implement a runtime check like that, I could try to do it, otherwise it's a question if you're willing to sacrifice that over type safety. |
Did you try to call super().init() |
the init() is only called if you instanciate the class, so something sounds wrong. |
Enums use metaclasses, so logic from ordinary classes cannot be applied, If you try: class Example(enum.Enum):
def __init__(self, value):
raise Exception("need __init__")
A = "A"
B = "B" You will get |
Seems you are right. |
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.
LGTM, thanks
Looking forward to your next PR.
Closes #1741, went a bit further and converted all static classes to enums. This should provide type safety while maintaining compatibility with raw ints and strings.
Changelog:
ModbusStatus
> inherits fromint
andenum.Enum
Endian
> inherits fromstr
andenum.Enum
ModbusPlusOperation
> inherits fromint
andenum.Enum
DeviceInformation
> inherits fromint
andenum.Enum
MoreData
> inherits fromint
andenum.Enum