Repository navigation
OrderedDescriptor and OrderedDescriptorContainer - #3679
Conversation
|
Any thoughts about this? |
|
Sorry -- I had meant to have a look at this and haven't had a chance (and this week is awful for me). Don't want to hold up the works, though. |
|
Sorry also been busy but I like the idea and simplification in coordinates. Will try for a more detailed look this week. |
|
Ack, it's okay. Now that I'm in it, this week is awful for me too; I don't expect I'll need this 'til after Leiden. |
|
I haven't attempted to understand all the details of the new code, but I note that it is extremely well documented and so the subtleties should be transparent to future maintainers! From the coordinates perspective I've looked through the changes and confirmed that things look reasonable. Given that tests are passing I'm 👍 on this. @eteq - do you want to weigh in on this? |
|
I guess to help guide any further review, there are two main things about this I'm not 100% certain about and would like feedback on (and these can always be changed later if need be). Both have to do with how the Descriptor class hooks up with classes it's used on. The first is the class FrameAttribute(OrderedDescriptor):
_class_attribute_ = 'frame_attributes'
# ...
class FrameMeta(OrderedDescriptorContainer):
#...
class BaseFrame(metaclass=FrameMeta):
# Default empty frame_attributes; in principle it's not necessary to define
# this default, but in practice it's pretty convenient to, and makes more clear
# that this attribute exists (otherwise it will come in 'magically' via the metaclass
frame_attributes = OrderedDescriptor()This of course means that if I wanted to use class BaseFrame(metaclass=FrameMeta):
_ordered_descriptors_ = {FrameAttribute: 'frame_attributes'}
frame_attributes = OrderedDict()etc. This would map ordered descriptor classes to the names of attributes on the class. It might also be able to automatically set up the default, so that the last line in the above example is unnecessary. The other question is what the default behavior should be for inheritance. I chose, as the default, for subclasses to not inherit OrderedDescriptor collections from their parent classes, since this is the (current) behavior of |
|
On the first question, I prefer the current implementation over the option of something like On the second question, my natural inclination would be for the ordered descriptor collections to inherit from their parent classes, but it's not a huge deal either way. |
|
@eteq As a stakeholder in the coordinates package do you have any opinion on this (or other stakeholders in coordinates?) I think overall the changes to coordinates in this are very minimal, and mostly result in code simplification. As far as I can tell the behavior of frame attributes is still correct. |
9c72af9 to
45d4a46
Compare
|
Rebased on master. Going to go ahead and merge this soon, after I add a little more documentation. |
|
👍 |
…ainer and OrderedParameter, respectively. This required removing a bunch of code that checked for consistency between the param_names attribute and the names of Parameter attributes. However, I think these checks are mostly moot at this point, and were needed more for transitioning of the interface between versions 0.3 and 0.4 and up. I think with any newer code it's not an issue (and even with older code this was a check against developer error, not user error). To be clear, I updated the documentation. Also had to remove one test that was no longer relevant.
… currently implemented.
…scriptorContainer for FrameAttribute and BaseFrame. This *mostly* obviates the need for BaseFrame.get_frame_attr_names(). However, the frame_attributes dict created by OrderedDescriptorContainer is different, as it maps to the actual descriptor objects themselves (retrieved from BaseFrame.__dict__ rather than getattr(BaseFrame, attr_name)). There is a lot of code in the coordinates package that assumes the latter behavior, so for now I left BaseFrame.get_frame_attr_names() in place, and just adapted it to use the new interface.
…y/astropy-helpers#158, which is needed for the docs to build correctly. Also fixed several docstrings that weren't being handled correctly by Sphinx due to use of the InheritDocstrings metaclass (not exactly sure why it wasn't a problem previously though...).
45d4a46 to
0fa4bbb
Compare
|
Rebased this again--going to go ahead and merge soon as I get the green light from CI. I hoped that this would improve some of the problems with subclassing models, but it's still tricky due to deeper reasons (though it will help). I'll go ahead with this as is and address the model subclassing problems separately (#4035). |
OrderedDescriptor and OrderedDescriptorContainer
This PR implements two new classes that provide a generic implementation of a pattern that has come up in a couple places, and I anticipate using again. The pattern is having a class that implements some descriptor, which will be instantiated multiple times at the level of a class declaration, and where we want to be able to record the order in which those descriptors were created in the class definition.
The two examples of this in Astropy currently, are
Model, which uses theParameterdescriptor to declare parameters of a model, and theFrameAttributeclass used with coordinate frames in the coordinates package.I thought of trying to generalize this pattern because I recently started writing yet another class that worked exactly the same way, for a modeling update. It's worth noting that in Python 3 the
__prepare__magic method mostly supplants this pattern. But there are some advantages toOrderedDescriptor+OrderedDescriptorContainerover__prepare__, such as automatic assignment to a.nameattribute on the descriptors based on the name of the attribute they were assigned to. I think inheritance/subclassing is also handled pretty well here.For more details see the docstrings for
OrderedDescriptorandOrderedDescriptorContainer. This PR also updates the modeling package and the coordinates package to use these new classes. Feedback is appreciated.