traits
traits copied to clipboard
class_traits uses __base_traits__ instead of __class_traits__
I came across the following base class and subclass:
class Base(HasTraits):
a = Str("a")
class Child(Base):
a = "overridden"
If you try to inspect the default value for Child.a
:
> Child.class_traits()["a"].default
"a"
But I'd expect "overridden" to be returned instead.
If I access __class_traits__
instead, I get the value I expected:
> Child.__class_traits__["a"].default
"overridden"
(It was new to me that redefining the traits in a subclass is considered as redefining the traits with a new default value. See this branch.)
Turns out HasTraits.class_traits
is using __base_traits__
, not __class_traits__
:
https://github.com/enthought/traits/blob/ba7c10fa28666219e276c7eeeac7e3e7168a45c2/traits/has_traits.py#L3085-L3094
Is this intended? Or is this a bug?
My suspicion is that maybe https://github.com/enthought/traits/blob/ba7c10fa28666219e276c7eeeac7e3e7168a45c2/traits/has_traits.py#L633 should be setting into the base trait dict as well as the class trait dict? Either that or class_traits
should be using __class_traits__
as you suggest. But I'm not yet sure enough which of them is "right".
One thing I'd like to do is expose the actual class_traits and instance_traits dictionaries (the ctrait_dict
and itrait_dict
fields on a C has_traits_object
) that CHasTraits
is using, if only for debugging purposes. I don't think there's currently any clean way to get those dictionaries. More generally, as much as possible of cTrait
and CHasTraits
should be introspectable at some level.
And as far as I can tell, __base_traits__
and __class_traits__
are intentionally different in that __base_traits__
are the ones used when subclassing. I'm not convinced that the line @corranwebster identifies should be changed, but I do think we should probably link the class_traits
method to the __class_traits__
dictionary rather than the __base_traits__
dictionary. It would be helpful to go through ETS and identify uses of the class_traits
method to see if any of them would be adversely affected by such a change.
Yes I was under the same impression that __base_traits__
refers to the traits defined in the base classes, whereas __class_traits__
refers to the traits on the current(?) class.
I am wondering (going down the rabbit hole)... is HasTraits.traits
affected too? This line:
https://github.com/enthought/traits/blob/ba7c10fa28666219e276c7eeeac7e3e7168a45c2/traits/has_traits.py#L3018
is
HasTraits.traits
affected too?
Likely, yes. The traits that a HasTraits
instance is actually using on attribute lookup are in the ctrait_dict
and itrait_dict
fields; I'd expect those dictionaries to be the ones being used when reporting either class_traits
or traits
.