Take default value for Enum from allowed values#13
Take default value for Enum from allowed values#13takluyver wants to merge 1 commit intoipython:masterfrom
Conversation
If no default is explicitly specified and allow_none is False (the default), Enum currently causes an error if you instantiate the object owning it without supplying a value for it. This changes makes it take the first of the possible values as the default instead. If you want to force the code instantiating the class to supply a value, you can create the Enum with `default_value=None`.
|
-1 on this from me. As a user of traitlets for various random side projects, I'd always rather have to explicitly specify a default value than have the traitlet system try to guess what it thinks I might have meant. The failure mode when you forget to specify a default is easy to reproduce and straightforward to diagnose from the resulting stack trace. The failure mode when a traitlet unexpectedly has a default is that a value somewhere in your program has a value you didn't mean to supply, which is much more likely to cause unexpected behavior that's not easily traceable back to the root cause. |
|
I get Scott's argument on defensive programming. Although I would be +1 on this. I wanted to open the same PR also because HasTraits declarations with decorations gets longer and longer. Removing unnecessary arguments is beneficiary in that regard. Besides it is consistent with the documentation format for tuples where the first value is the default. |
|
The reason I ran into this is for https://github.com/jupyter/kerneltest, where traitlets are used to validate messages. All of the instances are created without specifying any values, and then the values from the messages are assigned to instance attributes to validate them. It seems wrong to specify a default value just to shut traitlets up, and it's definitely wrong to set This is admittedly something of an odd case, but I think the change is in keeping with the way traitlets generally work - if you specify However, I understand the defensive programming argument as well. Maybe it would be a useful compromise if it threw an error when you access the traitlet without having given it a value, rather than when you instantiate the object? I think that would work for my use case. |
|
@minrk proposed to postpone the instantiation of default values (and therefore their validation) to the first time it is accessed. It would probably make sense for your use case. |
|
In the simple case of a list or tuple, I think picking the first element by default is clear and correct behavior. But when it's a set, the initial value would be randomized, which isn't good. The fact that the initial value is different whether allow_none is True or not suggests that this is hazardous, too. If you can delay the raise until first access prior to assignment, that would solve the problem without adding any inappropriate guessing. |
|
Hum, I don't understand how the default value should depend on whether allow_none is True or False? |
|
@SylvainCorlay in this implementation as it is, when allow_none is True, the default value is None. Otherwise, the default value is the first element. At the very least, I don't think the default value should depend on whether None is allowed. |
|
Ok, then I guess it would make sense that the default value is the first one of the options in both cases. |
Alternative to ipythongh-13 Previously, if: - The traitlet class does not specify a default value, - The use of the traitlet does not provide a default value, - The class using the traitlet does not have a _foo_default method, and - The instantiation of that class does not provide a value for the traitlet then the traitlet would try to set its value to the undefined default, usually causing an error. With this change, it will skip that, so the traitlet will have no value. If it is accessed before a value has been set, the error will occur then instead. This allows Enums with no default value, which I want for kernelspec. `Instance` traitlets are not affected - they will still create an instance of the specified class when the class using them is instantiated.
There was a problem hiding this comment.
You could also do
if default_value is NoDefaultSpecified:
if self.values:
default_value = next(iter(self.values))
else:
default_value = Undefinedand have it all not depend and allow_none.
|
Superseded by #14. |
If no default is explicitly specified and allow_none is False (the default), Enum currently causes an error if you instantiate the object owning it without supplying a value for it. E.g.
This changes makes it take the first of the possible values as the default instead. If you still want to force the code instantiating the class to supply a value, you can create the Enum with
default_value=None.