Skip to content

Avoid resorting units when converting to strings - #14439

Merged
pllim merged 1 commit into
astropy:mainfrom
mhvk:units-format-no-extra-sorting
Mar 9, 2023
Merged

pllim merged 1 commit into
astropy:mainfrom
mhvk:units-format-no-extra-sorting

Conversation

@mhvk

@mhvk mhvk commented Feb 22, 2023 •

Copy link
Copy Markdown
Contributor

When converting units to strings, the order of the base units is now always the same as it is in the unit itself: by decreasing power to which the unit is raised, and then alphabetical. This avoids super-ugly representations such as beam-1 Jy (such as could happen for FITS; see #13217).

However, as can be seen from the PR, it also means some (doc)tests had to be adapted, and it can reasonably be foreseen that this will cause similar down-stream failures. Hence, opening as draft for now. EDIT: given initial positive feedback, changed to regular PR.

(Note based on #14437 for now; will rebase once that is in.) EDIT: rebased now previous format PRs are in.

Fixes #13217

@mhvk mhvk added io.fits units API change PRs and issues that change an existing API, possibly requiring a deprecation period labels Feb 22, 2023
@mhvk mhvk added this to the v5.3 milestone Feb 22, 2023
@mhvk
mhvk requested review from nstarman, olebole and saimn February 22, 2023 21:10
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see "When to rebase and squash commits".
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • Is a milestone set? Milestone must be set but we cannot check for it on Actions; do not let the green checkmark fool you.
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@github-actions

Copy link
Copy Markdown
Contributor

👋 Thank you for your draft pull request! Do you know that you can use [ci skip] or [skip ci] in your commit messages to skip running continuous integration tests until you are ready?

else:
raise ValueError(f"Syntax error parsing unit '{s}'")

@classmethod

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is really the main change. Since FITS and VOUNIT inherit from generic, this means that they had the same sorting -- undoing the more logical sorting in their classes. Indeed, the sorting that was done in FITS/VOUNIT just followed what CompositeUnit itself does anyway, so in that sense for those formats this change makes them behave as intended...

flam = u.erg / u.cm / u.cm / u.s / u.AA
x = u.format.VOUnit.to_string(flam)
assert x == "Angstrom**-1.cm**-2.erg.s**-1"
assert x == "erg.Angstrom**-1.s**-1.cm**-2"

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.

Yes, I like the new order. 😸

Comment thread docs/units/equivalencies.rst Resolved

@nstarman nstarman 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.

Overall I think this is a significant improvement and well worth changing tests downstream.

@mhvk
mhvk force-pushed the units-format-no-extra-sorting branch from cae748e to 2ed9d09 Compare February 23, 2023 00:43
@mhvk

mhvk commented Feb 23, 2023

Copy link
Copy Markdown
Contributor Author

Well, with one approval, I'll open this for general review! Thanks, @nstarman!

@mhvk
mhvk marked this pull request as ready for review February 23, 2023 00:44
@mhvk
mhvk requested a review from a team as a code owner February 23, 2023 00:44
@mhvk
mhvk force-pushed the units-format-no-extra-sorting branch 2 times, most recently from c24ea1a to 6ee3e5c Compare February 28, 2023 14:26
@mhvk

mhvk commented Feb 28, 2023

Copy link
Copy Markdown
Contributor Author

Rebased this PR that removes extra sorting when units are represented as strings with unit.to_string(). In general, this seems to improve the readability of the units (especially FITS and VOUNIT), but it implies a lot of small changes (and will probably cause downstream doctests to fail). Two questions:

  1. Does this need a what's new entry?
  2. I wondered a bit whether one could go for a "standard" representation for anything for which we have a physical type (e.g., "erg/(s cm2 A)" rather than "erg/(A s cm2)" as it is now). Not totally trivial since the physical types do not store how their unit is represented currently. Overall, I felt this might be a good idea but is more work than I have time for now. Of course, it is supplementary to this PR, so can be done after. But ideally we change the format very rarely, so if we merge the present PR, further changes should preferably happen before 5.3 is released.

@nstarman

nstarman commented Mar 1, 2023

Copy link
Copy Markdown
Member
  1. Does this need a what's new entry?

I think so, esp if point 2 isn't completed by v5.3!

I wondered a bit whether one could go for a "standard" representation for anything for which we have a physical type (e.g., "erg/(s cm2 A)" rather than "erg/(A s cm2)" as it is now).

I think that would be fantastic!

@WilliamJamieson WilliamJamieson 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.

Modeling changes look good to me

@mhvk
mhvk force-pushed the units-format-no-extra-sorting branch from 6ee3e5c to 6def838 Compare March 8, 2023 20:55
@mhvk

mhvk commented Mar 8, 2023

Copy link
Copy Markdown
Contributor Author

Thanks! I've added a what's-new entry (and rebased for good measure). It is probably not a bad idea to merge this well before the feature freeze date, so we can get some feedback (e.g., if many doctests break). That also gives some time to experiment with possibly using a default representation based on physical type.

@pllim

pllim commented Mar 8, 2023

Copy link
Copy Markdown
Member

Need to fix doc warning:

docs/whatsnew/5.3.rst:156: WARNING: Duplicate explicit target name: "whatsnew-5.3-unit-formats-fraction".

@pllim

pllim commented Mar 11, 2023

Copy link
Copy Markdown
Member

I don't know. I too agree that this PR is good improvement. I need to sleep on this over the weekend.

@nstarman

Copy link
Copy Markdown
Member

What about the UNIT_CMP flag that can be turned on globally. It wouldn't require Astropy to be installed since it would be a regex to find <Quantity and then parse to find the unit bit and then rearrange based on the new rules. Ugh sounds like a fair bit of work, but I think it would solve all pain points except writing it.

@mhvk

mhvk commented Mar 11, 2023

Copy link
Copy Markdown
Contributor Author

One possible issue is that the unit is not only printed as part of <Quantity ...> -- think table columns (or the perhaps the second example listed above).

Aside, could one use something like .. doctest-requires : astropy>=5.3? Or can one not use version information?

@pllim

pllim commented Mar 13, 2023

Copy link
Copy Markdown
Member

.. doctest-requires : astropy>=5.3

Unfortunately, no... scientific-python/pytest-doctestplus#193

But somehow you can do it via doctest_subpackage_requires which isn't as flexible but might be better than nothing.

@mhvk

mhvk commented Mar 13, 2023

Copy link
Copy Markdown
Contributor Author

You mean this? scientific-python/pytest-doctestplus#112

Actually, it may be a reasonable solution to tell people that they can set the style with a version constraint in setup.cfg (if I understood it correctly).

@pllim

pllim commented Mar 13, 2023

Copy link
Copy Markdown
Member

Yes, but alas you cannot just ask doctestplus to only require certain astropy version for that one line, it is whole module. Not ideal but might be the best we can do for now.

@mhvk

mhvk commented Mar 13, 2023

Copy link
Copy Markdown
Contributor Author

I don't think that is that bad -- it shows that examples work with the most recent version of astropy; presumably, the tests cover the rests.

@pllim

pllim commented Mar 13, 2023

Copy link
Copy Markdown
Member

If you are curious on how I am handling this downstream, please see the following PRs and feel free to comment on them if you have better ideas. Thanks!

@mhvk

mhvk commented Mar 14, 2023

Copy link
Copy Markdown
Contributor Author

Hey, so one can do __doctest_requires__ = {"BlackBody": ["astropy<5.3"]}? That's pretty nice at least for the python files! And I think the .rst files being covered in setup.cfg is not that bad either.

So, I guess the to-do item may be to have this as part of either the what's-new or the API change fragment...

@pllim

pllim commented Mar 14, 2023

Copy link
Copy Markdown
Member

Might be easier to explain in What's New. Do you want to do a follow-up PR? If not, I can take a stab when I have time.

@mhvk

mhvk commented Mar 14, 2023

Copy link
Copy Markdown
Contributor Author

Makes sense. If you can have a stab, that would be great - I'll be mostly out of action until term ends in April...

pllim added a commit to pllim/astropy that referenced this pull request Mar 14, 2023
@pllim

pllim commented Mar 14, 2023

Copy link
Copy Markdown
Member

Please see #14526

@bsipocz

bsipocz commented Apr 28, 2023

Copy link
Copy Markdown
Member

This bit astroquery as well, and the suggested workaround in setup.cfg is not exactly nice (we do want to test both old and new astropy versions).

@mhvk

mhvk commented Apr 28, 2023

Copy link
Copy Markdown
Contributor Author

@bsipocz - sorry to hear that this bit you... I love the principle of doctests, of ensuring that what the user will see when they run some example is actually what is in the documentation, but it does seem they raise the barrier rather a lot for making changes to how output looks - one shouldn't have to think of formatting as part of the API!

@bsipocz

bsipocz commented Apr 28, 2023

Copy link
Copy Markdown
Member

OTOH, if formatting is not important enough to consider backward compatibility, it may not be worth changing it and causing such widespread issues downstream, at least not without also adding tools that provide reasonable workarounds (globally skipping doctesting in rst files is not really a nice workaround).

@mhvk

mhvk commented Apr 28, 2023 •

Copy link
Copy Markdown
Contributor Author

It's a hard one - the first FITS unit of beam^-1 Jy really had to go; I guess we could have left it at that and minimized the pain by not changing generic as well.

On balance, we felt it was worth it. It is a bit like numpy in 1.13 getting around to finally clean-up the number of significant digits that get included in output (following python doing the same). Output looks much better now but it was a gigantic pain (even with FLOAT_CMP; we thought about an equivalent for units, but it is just impossible).

@WilliamJamieson

Copy link
Copy Markdown
Contributor

Unit string changes will break ASDF unit validation as jsonschema only exactly matches the listed unit string. Resulting in the need for spacetelescope/roman_datamodels#258. I think this maybe the only project currently using ASDF's unit support, so this should not be a big issue right now. In the future, please tag me on any unit string changes.

@pllim

pllim commented Aug 8, 2023

Copy link
Copy Markdown
Member

@WilliamJamieson , you can always add yourself to the "units" section in codeowners, then you will get pinged automatically. FYI.

@mhvk

mhvk commented Aug 8, 2023

Copy link
Copy Markdown
Contributor Author

@WilliamJamieson - I think this is going to be the last string change in a very long time.... Hopefully mostly because it is now as "right" as it can be, but certainly also to avoid again causing breakage and thus loss of time that could be better spent elsewhere...

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

Labels

API change PRs and issues that change an existing API, possibly requiring a deprecation period io.fits modeling nddata Ready-for-final-review units

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regarding FITS standard definition for 'Jy/beam'

7 participants