Repository navigation
Fix #8490: FITS serialization for SunPy coordinates - #8548
Conversation
|
If such registration is necessary, can we do it within |
|
@ayshih Thank you for your guidance, Using init_subclass on SunPyBaseCoordinateFrame would be much better than my current approach it would automatically register any new frames without needing a separate module. |
|
for pushing it upstream to BaseCoordinateFrame in Astropy, will that be in the scope of this PR?? |
|
It'd be fine to fix it here, and then try to push it upstream to Astropy at some future date. How does Astropy register their built-in frames, and if it's not through |
|
@ayshih I looked into how Astropy handles this. It doesn't use |
|
Astropy's own frames like ICRS, Galactic pass through because they all start with |
| if isinstance(cls, type) and issubclass(cls, BaseCoordinateFrame): | ||
| key = f"{cls.__module__}.{cls.__name__}" | ||
| frame_classes[key] = cls | ||
| return tuple(frame_classes.values()) |
There was a problem hiding this comment.
Why create the a dictionary if just returning the values tuple? I think if you did return the dictionary here you could avoid having to recreate it later in ~L43 e.g f"{cls.__module__}.{cls.__name__}"?
| from astropy.io.misc.yaml import AstropyDumper, AstropyLoader | ||
| except ImportError: | ||
| # PyYAML is optional in Astropy, so skip registration if unavailable. | ||
| return |
There was a problem hiding this comment.
I'm pretty sure it's core dependency of astropy?
|
Yea the relevant code block as linked to by @Amityush-lgtm and since we can't change the namespace of our coords it looks like the only way is to add it to |
|
Thanks for the review @samaloney I have implemented the approach as per @ayshih suggestion i replaced |
85ba7ea to
ecde9cf
Compare
|
Done! Let me know your thoughts on this @ayshih @samaloney |
samaloney
left a comment
There was a problem hiding this comment.
I think this nearly good to go, just few small comments
|
@samaloney, I have made the suggested changes. |
| if hasattr(table_serialize, "__construct_mixin_classes"): | ||
| existing_classes = getattr(table_serialize, "__construct_mixin_classes") | ||
| if cls_name not in existing_classes: | ||
| setattr(table_serialize, "__construct_mixin_classes", existing_classes + (cls_name,)) |
There was a problem hiding this comment.
I think it's safe to assume that __construct_mixin_classes exists. I also think that using getattr()/setattr() is only useful if we are anticipating __construct_mixin_classes not being a variable, but it's difficult to guess the future. Can we keep things simple:
| if hasattr(table_serialize, "__construct_mixin_classes"): | |
| existing_classes = getattr(table_serialize, "__construct_mixin_classes") | |
| if cls_name not in existing_classes: | |
| setattr(table_serialize, "__construct_mixin_classes", existing_classes + (cls_name,)) | |
| if cls_name not in table_serialize.__construct_mixin_classes: | |
| table_serialize.__construct_mixin_classes += (cls_name,) |
There was a problem hiding this comment.
Argh, the problem is that the variable name has two leading underscores, which unfortunately triggers Python's private-name-mangling logic when accessed in a class definition. I suggest adding a comment for future maintenance.
You can still remove the hasattr() check.
| if hasattr(table_serialize, "__construct_mixin_classes"): | |
| existing_classes = getattr(table_serialize, "__construct_mixin_classes") | |
| if cls_name not in existing_classes: | |
| setattr(table_serialize, "__construct_mixin_classes", existing_classes + (cls_name,)) | |
| # We have to use getattr()/setattr() to avoid triggering Python name mangling | |
| existing_classes = getattr(table_serialize, "__construct_mixin_classes") | |
| if cls_name not in existing_classes: | |
| setattr(table_serialize, "__construct_mixin_classes", existing_classes + (cls_name,)) |
There was a problem hiding this comment.
Got it! I've updated the PR to use getattr() and added the comment.
|
Thanks for taking the time to review this |
Co-authored-by: Shane Maloney <[email protected]>
7d1ca71 to
5cc57d4
Compare
|
I'm going to have to vote -0 on this, the setting of a variable which someone decided to prefix with a double underscore feels really dirty. I feel like this is something we should really work with astropy to fix properly, i.e. address astropy/astropy#13689. |
Co-authored-by: Albert Y. Shih <[email protected]>
ayshih
left a comment
There was a problem hiding this comment.
This approach is not ideal, but I feel that it is acceptable
|
Thank you for the review and the guidance @ayshih . I agree its not a long term fix but i'm glad its acceptable for now and I'll keep an eye on that Astropy issue for a cleaner fix in the future. |
|
Hum the py312-oldestdeps fail seems real and related to this PR, going to assume something different in older version of |
|
@samaloney I looked into the failure and found that older Astropy versions don't have the Im thinking to update the code to handle this like manually collect all the frame's data like longitude, latitude and observation time and put them into a dictionary so it works on older versions and fix the tests to skip a few tricky cases that only work on newer Astropy. Will this be fine? Let me know your thoughts |
|
Hey @Amityush-lgtm ok that make sense, what version of astropy was |
|
8.0 should have a minimum of 6.1 |
|
Another failure in oldestdeps was due to older Astropy using |
|
@samaloney The oldestdeps fix worked. The remaining failures are unrelated to coordinate serialization, let me know if any other changes are required. |

PR Description
Fixes #8490
This PR resolves an issue where writing or reading SunPy coordinate frames to and from FITS files using Astropy tables (QTable) was crashing due to missing serialization registrations.
What Changed:
init_subclasstoSunPyBaseCoordinateFrameinsunpy/coordinates/frames.py. This ensures that any new coordinate frame subclass is automatically registered for serialization without needing manual configuration.init_subclassnow configures Astropy’s QTable processing and registers the correct PyYAML handlers so frames save and load exactly as they should.test_table_serialization.pyto properly verify FITS reading and writing for both single observer and array observer.AI Assistance Disclosure
AI tools were used for:
AI was used to help draft the initial version of the coordinate serialization fix and some unit tests. I have fully reviewed and manually verified the behaviour via tests
@samaloney, Let me know your thoughts on this. Happy to make changes!