traits icon indicating copy to clipboard operation
traits copied to clipboard

Remove default_value_type inference from TraitType subclasses

Open mdickinson opened this issue 2 years ago • 7 comments

I've created a series of PRs aimed at bypassing the default_value_type inference code for TraitType subclasses. See #1531, #1532, #1536.

Code link: https://github.com/enthought/traits/blob/9f934334668c6c0bf1e2866d6a81417275bbc255/traits/trait_type.py#L34-L52

Rationale:

  • making Traits less DWIMmy; in general we want to make the Traits codebase more predictable and reduce the number of corner cases with potentially surprising behaviour
  • code complexity: if we can remove the _infer_default_value_type function completely then some circular import problems go away - the dependence of that function on TraitListObject, TraitDictObject and TraitSetObject in particular is problematic.
  • performance (minor): in the vast majority of cases we go through the inference code even when it's clear from context that the default_value_type should be constant. By setting default_value_type up front we avoid that code path.

Steps:

  • [ ] Make sure that none of the built-in TraitType subclasses are using the default value type inference
    • [x] Deal with obviously constant defaults: #1531, and a few more in #1539
    • [x] Deal with Any: #1532 (this is the only case where list and dict default types are of interest)
    • [x] Deal with BaseClass and its subclasses: #1536 (some care required in BaseInstance)
    • [x] Deal with Constant: #1540
    • [x] Deal with TraitType subclasses in tests: #1539
    • [x] Determine whether Symbol needs changes: it doesn't - Symbol is deprecated in #1542
    • [x] Deal with Event and Disallow (related: #1546)
    • [x] Deal with Delegate and its subclasses.
  • [ ] Loudly deprecate the use of default value type inference for external TraitType subclasses
  • [ ] In Traits 7.0, replace default_value_type = DefaultValue.unspecified with default_value_type = DefaultValue.constant in the TraitType base class, and clean up the other classes accordingly.

mdickinson avatar Sep 20 '21 09:09 mdickinson

After #1531, #1532, #1536 and #1539, the following TraitType subclasses still make use of the type inference. (This list may not be exhaustive - it only covers the trait types for which the default value is exercised by the test suite.)

Constant
Delegate (and its subclasses)
Disallow
Event
ReadOnly

mdickinson avatar Sep 20 '21 10:09 mdickinson

You seem to have missed AbstractArray here.

rahulporuri avatar Sep 20 '21 12:09 rahulporuri

Yes, I need to look into that. I find it hard to believe that we never access the default value for an Array trait within the test suite.

mdickinson avatar Sep 20 '21 13:09 mdickinson

Ah, AbstractArray overrides get_default_value, so it never encounters that code. So there's nothing to do for AbstractArray and its subclasses.

mdickinson avatar Sep 20 '21 13:09 mdickinson

The other notable oddity is Either, which overrides the as_ctrait method, so also doesn't invoke TraitType.get_default_value. (It's possible that Either shouldn't be a TraitType subclass at all.)

mdickinson avatar Sep 20 '21 13:09 mdickinson

Constant is dealt with in #1540; Readonly is addressed in an updated version of #1531. That just leaves Event, Disallow, and Delegate and its subclasses.

As another check, here are the registered (direct) subclasses of TraitType after the end of the test run:

>>> [cls.__name__ for cls in TraitType.__subclasses__() if cls.default_value_type == DefaultValue.unspecified]
['Disallow', 'Delegate', 'Event', 'Either', 'Symbol', 'UUID', 'AbstractArray']

As discussed above, Either and AbstractArray don't need any change. UUID similarly overrides get_default_value, so doesn't make any use of the default_value_type attribute and doesn't need any change. Symbol may need some work.

mdickinson avatar Sep 20 '21 13:09 mdickinson

Bumping the remainder of this for 6.4.0

mdickinson avatar Oct 08 '21 11:10 mdickinson