Skip to content

[#11094] Deprecate and remove use of OrderedDescriptor - #11099

Merged
mhvk merged 8 commits into
astropy:masterfrom
embray:issue-11094
Jan 16, 2021
Merged

mhvk merged 8 commits into
astropy:masterfrom
embray:issue-11094

Conversation

@embray

@embray embray commented Nov 27, 2020 •

Copy link
Copy Markdown
Member

Fixes #11094. Builds on top of #11098 but they could be separated I think.

Note, this does not attempt to remove any metaclasses in favor of __init_subclass__ as discussed somewhat in #11090. That should be handled elsewhere for coordinates

Completes the work of #11090 to remove FrameMeta since it is no longer used.

@embray

embray commented Nov 27, 2020

Copy link
Copy Markdown
Member Author

Looks like I forgot to update my master branch because I didn't have #11090 incorporated yet. I'll rebase.

@mhvk mhvk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks all good to me - nice to have things simpler and less hidden (well, really there are hidden inside python now, of course...).

Does indeed need an entry under "API changes"

@adrn

adrn commented Nov 30, 2020

Copy link
Copy Markdown
Member

Great - thanks @embray! Agreed that this looks good and just requires a changelog entry.

@ayshih

ayshih commented Nov 30, 2020

Copy link
Copy Markdown
Contributor

Not a huge deal, but I believe this PR results in incorrect behavior when a frame class subclasses two different subclasses of BaseCoordinateFrame. I'll try to craft a minimal example.

@ayshih

ayshih commented Nov 30, 2020 •

Copy link
Copy Markdown
Contributor

Here you go:

>>> from astropy.coordinates import BaseCoordinateFrame, Attribute

>>> class Frame1(BaseCoordinateFrame):
>>>     attr1 = Attribute()
>>> class Frame2(BaseCoordinateFrame):
>>>     attr2 = Attribute()

>>> class Frame3(Frame1, Frame2):
>>>     pass
>>> Frame3.frame_attributes
{'attr1': <astropy.coordinates.attributes.Attribute at 0x1bfded96248>}

Note that attr2 is not picked up. I presume this is because __init_subclass__() – which is intended to accumulate all of the frame attributes – isn't actually called multiple times even though there are multiple subclasses.

For comparison, on master:

>>> Frame3.frame_attributes
OrderedDict([('attr1',
              <astropy.coordinates.attributes.Attribute at 0x29bb9e74348>),
             ('attr2',
              <astropy.coordinates.attributes.Attribute at 0x29bbad9dbc8>)])

@embray

embray commented Nov 30, 2020

Copy link
Copy Markdown
Member Author

(Oops, accidentally pushed commits for a different branch)

@embray

embray commented Nov 30, 2020

Copy link
Copy Markdown
Member Author

Thanks for the example @ayshih. I had thought about this case, but since it didn't happen to come up in any of the Astropy tests I assumed it maybe wasn't a usecase that was needed. Maybe it just wasn't tested because this case was tested implicitly by the use of OrderedDescriptor. But I completely agree with you on how this should work. I'll fix it and add a test.

@embray embray changed the title [#11094] Deprecate and remove use of OrderedDescriptor WIP: [#11094] Deprecate and remove use of OrderedDescriptor Nov 30, 2020
@astrojuanlu

Copy link
Copy Markdown
Member

Out of curiosity @ayshih, what would be the use case of subclassing two different frames?

@astrojuanlu

Copy link
Copy Markdown
Member

(Also, gh-11098 was merged, so this could be rebased)

@embray

embray commented Dec 31, 2020

Copy link
Copy Markdown
Member Author

@astrojuanlu thanks for the heads up, will do.

I'm also curious about @ayshih's use case of multiple inheritance of frames, but nevertheless they're right that it's a regression over the previous version that should be fixed. I'll try to finish that now.

@embray

embray commented Dec 31, 2020

Copy link
Copy Markdown
Member Author

Rebased and fixed the multiple inheritance case.

@embray embray changed the title WIP: [#11094] Deprecate and remove use of OrderedDescriptor [#11094] Deprecate and remove use of OrderedDescriptor Dec 31, 2020
@embray

embray commented Dec 31, 2020

Copy link
Copy Markdown
Member Author

Fixed the style check and added changelog entry.

@embray

embray commented Dec 31, 2020

Copy link
Copy Markdown
Member Author

In the changelog I referenced the original issue number, not the PR number. Is that what we're doing now?

Comment thread CHANGES.rst Outdated

@adrn adrn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! (apart from the changelog edit by @pllim). Very happy to be rid of the metaclass stuff in coordinates after this 😄.

copy.deepcopy(repr_info))

# Set the frame attributes
# TODO: Should this be made to use readonly_prop_factory as well or

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current functionality allows overriding .frame_attributes. Not that it's a good idea to allow this, but I think it's fine to leave functionality as is for now and reconsider this in a separate issue/PR.

@pllim

This comment has been minimized.

@adrn

adrn commented Dec 31, 2020

Copy link
Copy Markdown
Member

There are failures in modeling though.

I don't think those failures are caused by this PR!

@pllim

pllim commented Dec 31, 2020 •

Copy link
Copy Markdown
Member

You are right! Seems to be from #11108 that just got merged before this was rebased. Or due to upstream changes and the timing is coincidental.

@pllim

pllim commented Dec 31, 2020 •

Copy link
Copy Markdown
Member

Wait... Ugh, I think it is due to Scipy 1.6.0 that just got released. I'll submit a stop gap PR (see #11201).

@mhvk

mhvk commented Dec 31, 2020

Copy link
Copy Markdown
Contributor

Just a 🎆 from the sidelines (will light some real ones later...)

@ayshih

ayshih commented Jan 4, 2021

Copy link
Copy Markdown
Contributor

@astrojuanlu

Out of curiosity @ayshih, what would be the use case of subclassing two different frames?

@embray

I'm also curious about @ayshih's use case of multiple inheritance of frames

In principle, this could be useful for using class inheritance to manage common frame attributes. For example, there could be a base class that adds the equinox frame attribute rather than defining that attribute separately within each frame definition (and possibly introducing an inconsistency). It'd be particularly useful if there are any convenience methods that'd be useful to any frame with an equinox frame attribute, but not useful to any other frame.

In practice, Astropy already has cases of subclassing two different frames, although this may be a design oversight. Any frame created by SkyOffsetFrame subclasses both SkyOffsetFrame (which has the rotation and origin frame attributes) and the frame of the origin argument (which has its normal frame attributes, e.g., obstime). For example:

>>> import astropy.units as u
>>> from astropy.coordinates import SkyCoord, SkyOffsetFrame

>>> sc = SkyCoord(0*u.deg, 0*u.deg, frame='hcrs')
>>> so = SkyOffsetFrame(origin=sc)
>>> so
<SkyOffsetHCRS Frame (obstime=J2000.000, rotation=0.0 deg, origin=<HCRS Coordinate (obstime=J2000.000): (ra, dec) in deg
    (0., 0.)>)>

>>> so.__class__.__bases__
(astropy.coordinates.builtin_frames.skyoffset.SkyOffsetFrame,
 astropy.coordinates.builtin_frames.hcrs.HCRS)
>>> so.frame_attributes
OrderedDict([('obstime',
              <astropy.coordinates.attributes.TimeAttribute at 0x18959ce1e88>),
             ('rotation',
              <astropy.coordinates.attributes.QuantityAttribute at 0x18959cfb708>),
             ('origin',
              <astropy.coordinates.attributes.CoordinateAttribute at 0x18959df5b88>)])

@ayshih

ayshih commented Jan 4, 2021

Copy link
Copy Markdown
Contributor

Re SkyOffsetFrame, I say "design oversight" because for a similar frame in SunPy (RotatedSunFrame), I have recently decided to remove the inheritance of the frame class of the supplied coordinate. SkyOffsetFrame may not be able to make the same decision, of course.

Parameter.__set_name__ is used to set the names of Parameters upon class
initialization.

As before, the Model._parameters_ dict is intialized in
_ModelMeta.__new__ (which can't easily be replaced with
__init_subclass__ as it has other functionalities).

Although the removed function astropy.utils.misc.get_parameters was
technically public, it was arguably an implementation detail of
astropy.modeling.core and never should have been there; it is easily
replaced now with a one-liner.
astropy.coordinates

Now frame_attributes is simply set in FrameMeta.__new__, and Attribute
uses __set_name__.

A bit of other minor simplification in FrameMeta.__new__
…l, fixing

a regression from the previous version (since OrderedDescriptorContainer did
this automatically)

It should not be necessary to walk the entire MRO since this merging of
Attributes is already performed cumulatively by each base class's
__init_subclass__.
@embray

embray commented Jan 16, 2021

Copy link
Copy Markdown
Member Author

Fixed changelog conflict.

@mhvk

mhvk commented Jan 16, 2021

Copy link
Copy Markdown
Contributor

OK, just checked again and this all looks great. Let's get it in!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Simplify OrderedDescriptor[Container]

6 participants