Notes to John Parejko and my future self from pair programming 2023-03-29:
We'll want to deprecate all Mask constructors that take MaskPlaneDict, remove the default value for the MaskPlaneDict argument, and add a new variants of those constructors that instead take a std::shared_ptr<afw::image::detail::MaskDict> that defaults to nullptr.
For the first phase of this, we can provide just a collections.abc.Mapping pybind11 interface to afw::image::detail::MaskDict, and make the Python version of Mask.getMaskPlaneDict return that.
The Mapping-interface wrapper will preserve all Python usage of getMaskPlaneDict that treats the result as a snapshot just to be looked at but not modified.
By adding the new constructors we'll also preserve all Python usage of getMaskPlaneDict that just wants to pass the plane definitions from one Mask to another without modification.
Python usage of getMaskPlaneDict that tries to modify the result will intentionally break; this would include wholly-broken code that thinks it's modifying a view instead of a snapshot and possibly-valid code that's just trying to transfer modified mask plane definitions from one Mask to another. If there's a lot of the latter, we can extend the Mapping-interface wrappers a bit to support some mutation, but we'll also need to make sure such code first copies the dict (since at present it's already modifying a copy) and that it pays attention to docstrings.