Limit, document, test and deprecate default_value_type inference for 'Any' #1532
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The
Any
trait type currently goes through the normal inference fordefault_value_type
. The only cases where this inference is likely to produce something other thanDefaultValue.constant
are traits of the formAny(some_list)
orAny(some_dict)
. In those cases, we end up withDefaultValue.list_copy
andDefaultValue.dict_copy
respectively. This means that the default is copied for eachHasTraits
instance, so we end up with a per-instance non-shared default instead of a per-class shared default value.This PR moves the inference from the
TraitType
base class toAny.__init__
, and deprecates the use of theDefaultValue.list_copy
andDefaultValue.dict_copy
default value types. The intent is to useDefaultValue.constant
consistently in Traits >= 7.0.Rationale for the deprecation: the inference is already inconsistent in that it special-cases
list
anddict
instances but notset
instances. We could extend toset
(at some cost - we'd need a newDefaultValue
enum member and extra handling inctraits.c
), but that misses other mutable types, and just as with default values for Python functions, there's no realistic way that we can determine when a default value should be copied and when it shouldn't. The only sensible behaviour for Traits here is to follow Python's lead and not make copies when not explicitly asked to. If there are worries that this is a common failure mode, we could look into static analysis checking as a solution.I suspect that patterns of the form
Any(some_list)
orAny(some_dict)
are rather rare in real code; nevertheless, it seems prudent to have a deprecation period and only make the change in Traits 7.0.I did a search of Traits-using codebases available to me (both public and private) for the regex pattern
"= Any\("
. After discarding one false positive, I was left with 878 hits, most of which were simplyAny()
. The rest included:Any( [1, 2, 3 ] )
orAny([1, 2, 3])
in the traits documentation.Any( [] )
, in blockcanvasAny( {} )
orAny({})
, split between TraitsUI and blockcanvas, and 6 ofAny(dict())
, all in blockcanvas and codetoolsThe TraitsUI cases should be looked at; the rest are in outdated code and unlikely to be problematic.